From 366843b0020ce4296b60d38ff3cc6a2344ce1bf8 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Mon, 23 Sep 2013 13:50:54 +0200
Subject: [PATCH 01/26] [ADD] website.reload()
bzr revid: fme@openerp.com-20130923115054-bvx1ssa3pag6d56x
---
addons/website/static/src/js/website.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
index 8f2bd483ca8..594b0a645eb 100644
--- a/addons/website/static/src/js/website.js
+++ b/addons/website/static/src/js/website.js
@@ -37,7 +37,9 @@
});
return $.when.apply(null, dones);
};
-
+ website.reload = function () {
+ window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
+ };
var all_ready = null;
var dom_ready = website.dom_ready = $.Deferred();
From b783cbf4a628cbab5cc3bc7ec4a368970b6fcdd1 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Mon, 23 Sep 2013 13:54:17 +0200
Subject: [PATCH 02/26] [ADD] Translator
bzr revid: fme@openerp.com-20130923115417-bq20piq7f11pyjve
---
addons/website/static/src/css/editor.css | 21 +++
addons/website/static/src/css/editor.sass | 16 ++
.../static/src/js/website.translator.js | 151 ++++++++++++++++++
.../static/src/xml/website.translator.xml | 53 ++++++
4 files changed, 241 insertions(+)
create mode 100644 addons/website/static/src/js/website.translator.js
create mode 100644 addons/website/static/src/xml/website.translator.xml
diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css
index 127939f6caf..b6cc8505fed 100644
--- a/addons/website/static/src/css/editor.css
+++ b/addons/website/static/src/css/editor.css
@@ -107,6 +107,27 @@ table.editorbar-panel td.selected {
background-color: #b1c9d9;
}
+.oe_translate_examples li {
+ margin: 10px;
+ padding: 4px;
+}
+
+.oe_translatable_text {
+ outline: 1px solid black;
+}
+
+.oe_translatable_field {
+ outline: 1px dashed black;
+}
+
+.oe_translatable_text.oe_dirty, .oe_translatable_field.oe_dirty {
+ outline-color: red;
+}
+
+.oe_translatable_todo {
+ background: #ffffb6;
+}
+
/* ---- RTE ---- */
.oe_editable .btn {
-webkit-user-select: auto;
diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass
index 6eb47eab614..b5c0b21a197 100644
--- a/addons/website/static/src/css/editor.sass
+++ b/addons/website/static/src/css/editor.sass
@@ -93,6 +93,20 @@ table.editorbar-panel
td.selected
background-color: #b1c9d9
+// ---- TRANSLATIONS ---- {{{
+.oe_translate_examples li
+ margin: 10px
+ padding: 4px
+.oe_translatable_text
+ outline: 1px solid black
+.oe_translatable_field
+ outline: 1px dashed black
+.oe_translatable_text.oe_dirty, .oe_translatable_field.oe_dirty
+ outline-color: red
+.oe_translatable_todo
+ background: rgb(255, 255, 182)
+// }}}
+
/* ---- RTE ---- */
// bootstrap makes .btn elements unselectable -> RTE double-click can't know
@@ -481,3 +495,5 @@ $navbar_height: 51px
&.oe_ace_closed
width: 0
opacity: 0
+
+// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
new file mode 100644
index 00000000000..ac4c6d298d2
--- /dev/null
+++ b/addons/website/static/src/js/website.translator.js
@@ -0,0 +1,151 @@
+(function () {
+ 'use strict';
+
+ var website = openerp.website;
+ website.templates.push('/website/static/src/xml/website.translator.xml');
+
+ website.EditorBar.include({
+ events: _.extend({}, website.EditorBar.prototype.events, {
+ 'click a[data-action=js_website_translator]': function (ev) {
+ var self = this;
+ ev.preventDefault();
+ if (!localStorage['website_translator_nodialog']) {
+ var dialog = new website.TranslatorDialog();
+ dialog.appendTo($(document.body));
+ dialog.on('activate', this, function () {
+ dialog.$el.modal('hide');
+ this.translateMode();
+ });
+ } else {
+ this.translateMode();
+ }
+ },
+ }),
+ temporaryHack: function() {
+ // TODO: refactor once xmo's feature branch is merged
+ debugger
+ this.$buttons.edit.prop('disabled', true);
+ this.$('#website-top-view').hide();
+ this.$('#website-top-edit').show();
+ $('.css_non_editable_mode_hidden').removeClass("css_non_editable_mode_hidden");
+ this.$el.find('[data-action=snippet]').hide();
+ this.save = this.saveTranslations;
+ },
+ translateMode: function () {
+ var self = this;
+ this.temporaryHack();
+ // this.edit(); -- Will need a translation mode
+ this.translations = null;
+ openerp.jsonRpc('/website/get_view_translations', 'call', {
+ 'xml_id': $(document.documentElement).data('view-xmlid'),
+ 'context': website.get_context(),
+ }).then(function (translations) {
+ self.translations = translations;
+ self.processTranslatableNodes();
+ });
+ },
+ processTranslatableNodes: function () {
+ var self = this;
+ var $editables = $('[data-oe-model]')
+ .not('link, script')
+ .not('.oe_snippets,.oe_snippet, .oe_snippet *')
+ .not('[data-oe-type]');
+ $editables.each(function () {
+ self.transNode(this);
+ });
+ $('.oe_translatable_text').prop('contenteditable', true).on('paste', function () {
+ var node = $(this);
+ setTimeout(function () {
+ self.sanitizeNode(node);
+ }, 0);
+ });
+ $(document).on('blur keyup paste', '.oe_translatable_text[contenteditable]', function(ev) {
+ var $node = $(this);
+ setTimeout(function () {
+ // Doing stuff next tick because past and keyup are
+ // fired before the content is changed
+ if (ev.type == 'paste') {
+ self.sanitizeNode($node[0]);
+ }
+ if ($node.data('initial_content') !== $node.text()) {
+ $node.addClass('oe_dirty').removeClass('oe_translatable_todo');
+ }
+ }, 0);
+ });
+ },
+ sanitizeNode: function (node) {
+ node.text(node.text());
+ },
+ isTextNode: function (node) {
+ return node.nodeType === 3 || node.nodeType === 4;
+ },
+ isTranslatable: function (text) {
+ return text && _.str.trim(text) !== '';
+ },
+ markTranslatableNode: function (node) {
+ // TODO: link nodes with same content
+ node.className += ' oe_translatable_text oe_translatable_todo';
+ node.contentEditable = true;
+ $(node).data('initial_content', node.childNodes[0].data);
+ },
+ saveTranslations: function () {
+ var trans = {};
+ $('.oe_translatable_text.oe_dirty').each(function () {
+ var $node = $(this);
+ var text = $node.text();
+ var view_id = $(this).parents('[data-oe-model="ir.ui.view"]')
+ .not('[data-oe-type]').first().data().oeId;
+ if (!trans[view_id]) {
+ trans[view_id] = [];
+ }
+ trans[view_id].push({
+ initial_content: $node.data('initial_content'),
+ new_content: text
+ });
+ });
+ openerp.jsonRpc('/website/set_translations', 'call', {
+ 'data': trans,
+ 'lang': website.get_context()['lang'],
+ }).then(function () {
+ website.reload();
+ }).fail(function () {
+ // TODO: bootstrap alert with error message
+ alert("Could not save translation");
+ });
+ },
+ transNode: function (node, context) {
+ if (node.childNodes.length === 1
+ && this.isTextNode(node.childNodes[0])
+ && !node.getAttribute('data-oe-model')) {
+ this.markTranslatableNode(node);
+ } else {
+ for (var i = 0, l = node.childNodes.length; i < l; i ++) {
+ var n = node.childNodes[i];
+ if (this.isTextNode(n)) {
+ if (this.isTranslatable(n.data)) {
+ var container = document.createElement('span');
+ node.insertBefore(container, n);
+ container.appendChild(n);
+ this.markTranslatableNode(container);
+ }
+ } else {
+ this.transNode(n);
+ }
+ }
+ }
+ },
+ });
+
+ website.TranslatorDialog = openerp.Widget.extend({
+ events: _.extend({}, website.EditorBar.prototype.events, {
+ 'hidden.bs.modal': 'destroy',
+ 'click button[data-action=activate]': function (ev) {
+ this.trigger('activate');
+ },
+ }),
+ template: 'website.TranslatorDialog',
+ start: function () {
+ this.$el.modal();
+ },
+ });
+})();
diff --git a/addons/website/static/src/xml/website.translator.xml b/addons/website/static/src/xml/website.translator.xml
new file mode 100644
index 00000000000..f35cf583da9
--- /dev/null
+++ b/addons/website/static/src/xml/website.translator.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+ You are about to enter the translation mode.
+
+
+ In this mode you can not change the structure of the document, you can only translate text.
+
+
+ Here are the visuals used in order to help you in your translation flow:
+
+ -
+ Normal translatable content
+
+ -
+ ERP translatable object data
+
+ -
+ Translation TODO
+
+
+
+
+
+
+
+
+
+
+
+
From 3dc22cb54f94c65ee6cab322efc4c4b6b2e42c5b Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Mon, 23 Sep 2013 13:56:41 +0200
Subject: [PATCH 03/26] [FIX] Do not use text nodes if unnecessary
bzr revid: fme@openerp.com-20130923115641-2d4o4y3a7jkl5h9o
---
addons/website_contract/views/website_contract.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/website_contract/views/website_contract.xml b/addons/website_contract/views/website_contract.xml
index 040f2090eb9..36390ea05b2 100644
--- a/addons/website_contract/views/website_contract.xml
+++ b/addons/website_contract/views/website_contract.xml
@@ -39,7 +39,7 @@
@@ -264,8 +264,8 @@
@@ -288,7 +288,7 @@
We'll do our best to get back to you as soon as possible.
From bcd3f471ad16f4a9a2ebe7c75e12d3cc1eaf6e73 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Tue, 24 Sep 2013 12:23:05 +0200
Subject: [PATCH 10/26] [IMP] persistence of dialog opt out
bzr revid: fme@openerp.com-20130924102305-dxyxq56imz1xeul8
---
addons/website/static/src/js/website.translator.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index a4a5344aa85..d1701db5b2f 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -3,6 +3,7 @@
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.translator.xml');
+ var nodialog = 'website_translator_nodialog';
website.EditorBar.include({
start: function () {
@@ -17,10 +18,11 @@
},
edit: function () {
var self = this;
- if (!localStorage['website_translator_nodialog']) {
+ if (!localStorage[nodialog]) {
var dialog = new website.TranslatorDialog();
dialog.appendTo($(document.body));
dialog.on('activate', this, function () {
+ localStorage[nodialog] = dialog.$('input[name=do_not_show]').prop('checked') || '';
dialog.$el.modal('hide');
this.translate();
});
From f79d27e9a3a9fb1d16d2af44d3f0f8a1eb4abf1a Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Tue, 24 Sep 2013 21:06:37 +0200
Subject: [PATCH 11/26] [FIX] Update translations
bzr revid: fme@openerp.com-20130924190637-0qgzp58lzan8j1oc
---
addons/website/controllers/main.py | 35 ++++++++------
addons/website/static/src/css/editor.css | 4 ++
addons/website/static/src/css/editor.sass | 2 +
.../static/src/js/website.translator.js | 48 +++++++++++--------
addons/website/views/views.xml | 1 +
5 files changed, 57 insertions(+), 33 deletions(-)
diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py
index 39361cc1917..99ee5c9fb26 100644
--- a/addons/website/controllers/main.py
+++ b/addons/website/controllers/main.py
@@ -161,10 +161,13 @@ class Website(openerp.addons.web.controllers.main.Home):
return result
@website.route('/website/get_view_translations', type='json', auth='admin')
- def get_view_translations(self, xml_id, optional=False):
- view = request.registry.get("ir.ui.view")
- views = view._views_get(request.cr, request.uid, xml_id, request.context)
- return []
+ def get_view_translations(self, xml_id, lang=None):
+ lang = lang or request.context.get('lang')
+ views = self.customize_template_get(xml_id, optional=False)
+ views_ids = [view.get('id') for view in views if view.get('active')]
+ domain = [('type', '=', 'view'), ('res_id', 'in', views_ids), ('lang', '=', lang)]
+ irt = request.registry.get('ir.translation')
+ return irt.search_read(request.cr, request.uid, domain, ['id', 'res_id', 'value'], context=request.context)
@website.route('/website/set_translations', type='json', auth='admin')
def set_translations(self, data, lang):
@@ -174,17 +177,21 @@ class Website(openerp.addons.web.controllers.main.Home):
for t in trans:
initial_content = t['initial_content'].strip()
new_content = t['new_content'].strip()
- old_trans = irt.search_read(
- request.cr, request.uid,
- [
- ('type', '=', 'view'),
- ('res_id', '=', view_id),
- ('lang', '=', lang),
- ('src', '=', initial_content),
- ])
- if old_trans:
+ tid = t['translation_id']
+ if not tid:
+ old_trans = irt.search_read(
+ request.cr, request.uid,
+ [
+ ('type', '=', 'view'),
+ ('res_id', '=', view_id),
+ ('lang', '=', lang),
+ ('src', '=', initial_content),
+ ])
+ if old_trans:
+ tid = old_trans[0]['id']
+ if tid:
vals = {'value': new_content}
- irt.write(request.cr, request.uid, [old_trans[0]['id']], vals)
+ irt.write(request.cr, request.uid, [tid], vals)
else:
new_trans = {
'name': 'website',
diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css
index b6cc8505fed..da15826cd2d 100644
--- a/addons/website/static/src/css/editor.css
+++ b/addons/website/static/src/css/editor.css
@@ -124,6 +124,10 @@ table.editorbar-panel td.selected {
outline-color: red;
}
+.oe_translatable_text.oe_dirty:empty {
+ padding: 0 10px;
+}
+
.oe_translatable_todo {
background: #ffffb6;
}
diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass
index b5c0b21a197..00ee3df5014 100644
--- a/addons/website/static/src/css/editor.sass
+++ b/addons/website/static/src/css/editor.sass
@@ -103,6 +103,8 @@ table.editorbar-panel
outline: 1px dashed black
.oe_translatable_text.oe_dirty, .oe_translatable_field.oe_dirty
outline-color: red
+.oe_translatable_text.oe_dirty:empty
+ padding: 0 10px
.oe_translatable_todo
background: rgb(255, 255, 182)
// }}}
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index d1701db5b2f..39408234b6f 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -40,7 +40,7 @@
this.translations = null;
openerp.jsonRpc('/website/get_view_translations', 'call', {
'xml_id': $(document.documentElement).data('view-xmlid'),
- 'context': website.get_context(),
+ 'lang': website.get_context().lang,
}).then(function (translations) {
self.translations = translations;
self.processTranslatableNodes();
@@ -48,12 +48,13 @@
},
processTranslatableNodes: function () {
var self = this;
- var $editables = $('[data-oe-model]')
+ var $editables = $('[data-oe-model="ir.ui.view"]')
.not('link, script')
.not('.oe_snippets,.oe_snippet, .oe_snippet *')
.not('[data-oe-type]');
+
$editables.each(function () {
- self.transNode(this);
+ self.transNode(this, $(this).attr('data-oe-id')|0);
});
$('.oe_translatable_text').prop('contenteditable', true).on('paste', function () {
var node = $(this);
@@ -64,7 +65,7 @@
$(document).on('blur keyup paste', '.oe_translatable_text[contenteditable]', function(ev) {
var $node = $(this);
setTimeout(function () {
- // Doing stuff next tick because past and keyup are
+ // Doing stuff next tick because paste and keyup events are
// fired before the content is changed
if (ev.type == 'paste') {
self.sanitizeNode($node[0]);
@@ -84,26 +85,35 @@
isTranslatable: function (text) {
return text && _.str.trim(text) !== '';
},
- markTranslatableNode: function (node) {
+ markTranslatableNode: function (node, view_id) {
// TODO: link nodes with same content
- node.className += ' oe_translatable_text oe_translatable_todo';
+ node.className += ' oe_translatable_text';
+ node.setAttribute('data-oe-translation-view-id', view_id);
+ var content = node.childNodes[0].data.trim();
+ var trans = this.translations.filter(function (t) {
+ return t.res_id === view_id && t.value === content;
+ });
+ if (trans.length) {
+ node.setAttribute('data-oe-translation-id', trans[0].id);
+ } else {
+ node.className += ' oe_translatable_todo';
+ }
node.contentEditable = true;
- $(node).data('initial_content', node.childNodes[0].data);
+ $(node).data('initial_content', content);
},
save: function () {
var trans = {};
// this._super.apply(this, arguments);
$('.oe_translatable_text.oe_dirty').each(function () {
var $node = $(this);
- var text = $node.text();
- var view_id = $(this).parents('[data-oe-model="ir.ui.view"]')
- .not('[data-oe-type]').first().data().oeId;
- if (!trans[view_id]) {
- trans[view_id] = [];
+ var data = $node.data();
+ if (!trans[data.oeTranslationViewId]) {
+ trans[data.oeTranslationViewId] = [];
}
- trans[view_id].push({
- initial_content: $node.data('initial_content'),
- new_content: text
+ trans[data.oeTranslationViewId].push({
+ initial_content: data.initial_content,
+ new_content: $node.text(),
+ translation_id: data.oeTranslationId || null
});
});
openerp.jsonRpc('/website/set_translations', 'call', {
@@ -116,11 +126,11 @@
alert("Could not save translation");
});
},
- transNode: function (node, context) {
+ transNode: function (node, view_id) {
if (node.childNodes.length === 1
&& this.isTextNode(node.childNodes[0])
&& !node.getAttribute('data-oe-model')) {
- this.markTranslatableNode(node);
+ this.markTranslatableNode(node, view_id);
} else {
for (var i = 0, l = node.childNodes.length; i < l; i ++) {
var n = node.childNodes[i];
@@ -129,10 +139,10 @@
var container = document.createElement('span');
node.insertBefore(container, n);
container.appendChild(n);
- this.markTranslatableNode(container);
+ this.markTranslatableNode(container, view_id);
}
} else {
- this.transNode(n);
+ this.transNode(n, view_id);
}
}
}
diff --git a/addons/website/views/views.xml b/addons/website/views/views.xml
index b52cd5a5a9f..ca65fce6cf2 100644
--- a/addons/website/views/views.xml
+++ b/addons/website/views/views.xml
@@ -22,6 +22,7 @@
+
From 172ca5f213f50e2f0910c256508a54bb2c38725d Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Wed, 25 Sep 2013 11:31:57 +0200
Subject: [PATCH 12/26] [FIX] url_for on single language
bzr revid: fme@openerp.com-20130925093157-2rhvvhe2qsy9e68s
---
addons/website/website.py | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/addons/website/website.py b/addons/website/website.py
index 3530b8b77e2..a957117e15b 100644
--- a/addons/website/website.py
+++ b/addons/website/website.py
@@ -51,13 +51,15 @@ http.auth_methods['public'] = auth_method_public
def url_for(path, lang=None):
if request:
path = urljoin(request.httprequest.path, path)
- ps = path.split('/')
- lang = lang or request.context.get('lang')
- if ps[1] in request.context.get('langs'):
- ps[1] = lang
- if ps[1] not in request.context.get('langs'):
- ps.insert(1, lang)
- path = '/'.join(ps)
+ langs = request.context.get('langs')
+ if path[0] == '/' and len(langs) > 1:
+ ps = path.split('/')
+ lang = lang or request.context.get('lang')
+ if ps[1] in langs:
+ ps[1] = lang
+ else:
+ ps.insert(1, lang)
+ path = '/'.join(ps)
return path
def urlplus(url, params):
From e64c07f049a66bb4a689fe9d00db861749ddde91 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Wed, 25 Sep 2013 13:44:57 +0200
Subject: [PATCH 13/26] [FIX] Language in context for qweb translations
bzr revid: fme@openerp.com-20130925114457-ct5v0gefg6gd6ua8
---
addons/website/website.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/addons/website/website.py b/addons/website/website.py
index a957117e15b..35631a835f6 100644
--- a/addons/website/website.py
+++ b/addons/website/website.py
@@ -138,9 +138,10 @@ class website(osv.osv):
user_id=user.browse(cr, openerp.SUPERUSER_ID, uid),
)
- context = {
- 'inherit_branding': qweb_context.setdefault('editable', False),
- }
+ context = request.context.copy()
+ context.update(
+ inherit_branding=qweb_context.setdefault('editable', False),
+ )
# check if xmlid of the template exists
try:
From 0a679573fdc3e8b4faee9936e59d314edcb16a81 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Wed, 25 Sep 2013 17:42:14 +0200
Subject: [PATCH 14/26] [FIX] Use sourc-id in client translator
bzr revid: fme@openerp.com-20130925154214-mrktzf256zjkscy2
---
addons/website/static/src/js/website.translator.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index 39408234b6f..df0ef288b4f 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -54,7 +54,8 @@
.not('[data-oe-type]');
$editables.each(function () {
- self.transNode(this, $(this).attr('data-oe-id')|0);
+ var view_id = $(this).attr('data-oe-source-id') || $(this).attr('data-oe-id');
+ self.transNode(this, view_id|0);
});
$('.oe_translatable_text').prop('contenteditable', true).on('paste', function () {
var node = $(this);
From 7e085d4d5b2e05fd11b6d6b5dd51bb1a5b600f88 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Thu, 26 Sep 2013 11:25:43 +0200
Subject: [PATCH 15/26] [FIX] Do not activate language switcher on non
multilang controllers
bzr revid: fme@openerp.com-20130926092543-79b1e4v3gdttok6h
---
addons/website/views/views.xml | 2 +-
addons/website/website.py | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/addons/website/views/views.xml b/addons/website/views/views.xml
index c8f1cbbff30..3ce9260046e 100644
--- a/addons/website/views/views.xml
+++ b/addons/website/views/views.xml
@@ -78,7 +78,7 @@
Contact us
Sign in
-
+
diff --git a/addons/website/website.py b/addons/website/website.py
index 35631a835f6..f48cba9ecf2 100644
--- a/addons/website/website.py
+++ b/addons/website/website.py
@@ -108,6 +108,7 @@ class website(osv.osv):
request.context.update({
'lang': lang,
'langs': [lg.code for lg in request.website.language_ids],
+ 'multilang': request.multilang,
'is_public_user': is_public_user,
'is_master_lang': is_master_lang,
'editable': not is_public_user,
From da26fe77b9550128f034692a2a3c99997699d70b Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Thu, 26 Sep 2013 14:42:44 +0200
Subject: [PATCH 16/26] [IMP] Enabling ckeditor on translatable t-fields
bzr revid: fme@openerp.com-20130926124244-u3e3zhw0npmd4dae
---
.../static/src/js/website.translator.js | 43 +++++++++++++------
1 file changed, 31 insertions(+), 12 deletions(-)
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index df0ef288b4f..087e5c9f543 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -9,8 +9,6 @@
start: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
- // TODO: refactor once xmo's feature branch is merged
- // and make t-field's work as well as text translation
self.$('button[data-action=edit]').text("Translate");
self.$('[data-action=snippet]').hide();
self.$('#customize-menu-button').hide();
@@ -18,6 +16,7 @@
},
edit: function () {
var self = this;
+ var mysuper = this._super;
if (!localStorage[nodialog]) {
var dialog = new website.TranslatorDialog();
dialog.appendTo($(document.body));
@@ -27,18 +26,17 @@
this.translate();
});
} else {
- this.translate();
+ this.translate().then(function () {
+ // Disable non translatable t-fields
+ $('[data-oe-type][data-oe-translate=0]').removeAttr('data-oe-type');
+ mysuper.call(self);
+ });
}
},
translate: function () {
var self = this;
- // this.edit();
- this.$('#website-top-view').hide();
- this.$('#website-top-edit').show();
- $('.css_non_editable_mode_hidden').removeClass("css_non_editable_mode_hidden");
-
this.translations = null;
- openerp.jsonRpc('/website/get_view_translations', 'call', {
+ return openerp.jsonRpc('/website/get_view_translations', 'call', {
'xml_id': $(document.documentElement).data('view-xmlid'),
'lang': website.get_context().lang,
}).then(function (translations) {
@@ -54,10 +52,11 @@
.not('[data-oe-type]');
$editables.each(function () {
- var view_id = $(this).attr('data-oe-source-id') || $(this).attr('data-oe-id');
+ var $node = $(this);
+ var view_id = $node.attr('data-oe-source-id') || $node.attr('data-oe-id');
self.transNode(this, view_id|0);
});
- $('.oe_translatable_text').prop('contenteditable', true).on('paste', function () {
+ $('.oe_translatable_text').on('paste', function () {
var node = $(this);
setTimeout(function () {
self.sanitizeNode(node);
@@ -128,7 +127,14 @@
});
},
transNode: function (node, view_id) {
- if (node.childNodes.length === 1
+ // Mostly handling text and cdata nodes here
+ // so avoid jquery usage in this function
+ if (node.attributes['data-oe-type']) {
+ if (node.attributes['data-oe-translate'].value == '1') {
+ node.className += ' oe_translatable_field';
+ }
+ return;
+ } else if (node.childNodes.length === 1
&& this.isTextNode(node.childNodes[0])
&& !node.getAttribute('data-oe-model')) {
this.markTranslatableNode(node, view_id);
@@ -150,6 +156,19 @@
},
});
+ website.RTE.include({
+ start: function () {
+ this._super.apply(this, arguments);
+ this.$el.hide();
+ },
+ fetch_editables: function (root) {
+ $(root).click(function (ev) {
+ ev.preventDefault();
+ });
+ return $('[data-oe-translate=1]');
+ }
+ });
+
website.TranslatorDialog = openerp.Widget.extend({
events: _.extend({}, website.EditorBar.prototype.events, {
'hidden.bs.modal': 'destroy',
From 8c25a35cc6fc5380efa52ea0ec737883b63703e3 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Thu, 26 Sep 2013 15:17:08 +0200
Subject: [PATCH 17/26] [FIX] Save translations and t-fields
bzr revid: fme@openerp.com-20130926131708-16xmpbrx0vxlgbtw
---
addons/website/static/src/js/website.editor.js | 2 +-
.../website/static/src/js/website.translator.js | 16 ++++++++++++----
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js
index 41280199e45..8b15422b90d 100644
--- a/addons/website/static/src/js/website.editor.js
+++ b/addons/website/static/src/js/website.editor.js
@@ -282,7 +282,7 @@
});
}).get();
return $.when.apply(null, defs).then(function () {
- window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
+ website.reload();
});
},
/**
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index 087e5c9f543..14821af3072 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -8,6 +8,7 @@
website.EditorBar.include({
start: function () {
var self = this;
+ this.initial_content = {};
return this._super.apply(this, arguments).then(function () {
self.$('button[data-action=edit]').text("Translate");
self.$('[data-action=snippet]').hide();
@@ -70,12 +71,15 @@
if (ev.type == 'paste') {
self.sanitizeNode($node[0]);
}
- if ($node.data('initial_content') !== $node.text()) {
+ if (self.getInitialContent($node[0]) !== $node.text()) {
$node.addClass('oe_dirty').removeClass('oe_translatable_todo');
}
}, 0);
});
},
+ getInitialContent: function (node) {
+ return this.initial_content[node.attributes['data-oe-nodeid'].value];
+ },
sanitizeNode: function (node) {
node.text(node.text());
},
@@ -99,9 +103,13 @@
node.className += ' oe_translatable_todo';
}
node.contentEditable = true;
- $(node).data('initial_content', content);
+ var nid = _.uniqueId();
+ $(node).attr('data-oe-nodeid', nid);
+ this.initial_content[nid] = content;
},
save: function () {
+ var self = this;
+ var mysuper = this._super;
var trans = {};
// this._super.apply(this, arguments);
$('.oe_translatable_text.oe_dirty').each(function () {
@@ -111,7 +119,7 @@
trans[data.oeTranslationViewId] = [];
}
trans[data.oeTranslationViewId].push({
- initial_content: data.initial_content,
+ initial_content: self.getInitialContent(this),
new_content: $node.text(),
translation_id: data.oeTranslationId || null
});
@@ -120,7 +128,7 @@
'data': trans,
'lang': website.get_context()['lang'],
}).then(function () {
- website.reload();
+ mysuper.call(self);
}).fail(function () {
// TODO: bootstrap alert with error message
alert("Could not save translation");
From c67092bc3772bf42409330b0df9ab48ecdc9a986 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Thu, 26 Sep 2013 15:52:16 +0200
Subject: [PATCH 18/26] [WIP] load translation, mhhh
bzr revid: fme@openerp.com-20130926135216-f1b1k6kg04it9dzs
---
addons/website/static/src/js/website.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
index 70a3716f9e0..bc0db10ce88 100644
--- a/addons/website/static/src/js/website.js
+++ b/addons/website/static/src/js/website.js
@@ -80,7 +80,7 @@
$pagination.last().before(col);
});
- var page_start = page - parseInt(Math.floor((scope-1)/2));
+ var page_start = page - parseInt(Math.floor((scope-1)/2), 10);
if (page_start < 1 ) page_start = 1;
var page_end = page_start + (scope-1);
if (page_end > page_count ) page_end = page_count;
@@ -108,10 +108,10 @@
*/
website.ready = function() {
if (!all_ready) {
- all_ready = dom_ready.then(function () {
- // TODO: load translations
- return website.load_templates(templates);
- });
+ var tpl = website.load_templates(templates);
+ // var session;
+ // var trads = openerp._t.database.load_translations(session, ['website'], website.get_context().lang);
+ all_ready = $.when(dom_ready, tpl);
}
return all_ready;
};
From d322b64611c75d50601fc0599ebf607531d8e2b6 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Thu, 26 Sep 2013 16:54:13 +0200
Subject: [PATCH 19/26] [ADD] request.redirect()
bzr revid: fme@openerp.com-20130926145413-agxgeuwp89stxbbn
---
addons/website/website.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/addons/website/website.py b/addons/website/website.py
index f48cba9ecf2..70c0bea8fb0 100644
--- a/addons/website/website.py
+++ b/addons/website/website.py
@@ -12,6 +12,7 @@ import math
import traceback
from openerp.tools.safe_eval import safe_eval
from openerp.exceptions import AccessError, AccessDenied
+import werkzeug
import logging
logger = logging.getLogger(__name__)
@@ -102,6 +103,10 @@ class website(osv.osv):
return lang
def preprocess_request(self, cr, uid, ids, *args, **kwargs):
+ def redirect(url):
+ return werkzeug.utils.redirect(url_for(url))
+ request.redirect = redirect
+
is_public_user = request.uid == self.get_public_user().id
lang = self.get_lang()
is_master_lang = lang == request.website.default_lang_id.code
From 6d47823121f3129a48c6d317569f50fc32f2eb4f Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Thu, 26 Sep 2013 16:54:48 +0200
Subject: [PATCH 20/26] [IMP] website_sale multilang
bzr revid: fme@openerp.com-20130926145448-lvrfd6ma755jf549
---
addons/website_sale/controllers/main.py | 34 ++++++-------
addons/website_sale/views/website_sale.xml | 56 +++++++++++-----------
2 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index ac26662733c..96ce280cd33 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -209,7 +209,7 @@ class Ecommerce(http.Controller):
product_ids = [id for id in product_ids if id in product_obj.search(request.cr, request.uid, [("id", 'in', product_ids)], context=request.context)]
return product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context)
- @website.route(['/shop/', '/shop/category//', '/shop/category//page//', '/shop/page//'], type='http', auth="public")
+ @website.route(['/shop/', '/shop/category//', '/shop/category//page//', '/shop/page//'], type='http', auth="public", multilang=True)
def category(self, cat_id=0, page=0, **post):
if 'promo' in post:
@@ -250,7 +250,7 @@ class Ecommerce(http.Controller):
}
return request.website.render("website_sale.products", values)
- @website.route(['/shop/product//'], type='http', auth="public")
+ @website.route(['/shop/product//'], type='http', auth="public", multilang=True)
def product(self, cat_id=0, product_id=0, **post):
if 'promo' in post:
@@ -293,11 +293,11 @@ class Ecommerce(http.Controller):
}
return request.website.render("website_sale.product", values)
- @website.route(['/shop/add_product/', '/shop/category//add_product/'], type='http', auth="public")
+ @website.route(['/shop/add_product/', '/shop/category//add_product/'], type='http', auth="public", multilang=True)
def add_product(self, cat_id=0, **post):
product_id = request.registry.get('product.product').create(request.cr, request.uid,
{'name': 'New Product', 'public_categ_id': cat_id}, request.context)
- return werkzeug.utils.redirect("/shop/product/%s/?unable_editor=1" % product_id)
+ return request.redirect("/shop/product/%s/?unable_editor=1" % product_id)
def get_pricelist(self):
if not request.httprequest.session.get('ecommerce_pricelist'):
@@ -385,7 +385,7 @@ class Ecommerce(http.Controller):
return [quantity, order.get_total_quantity()]
- @website.route(['/shop/mycart/'], type='http', auth="public")
+ @website.route(['/shop/mycart/'], type='http', auth="public", multilang=True)
def mycart(self, **post):
order = get_current_order()
prod_obj = request.registry.get('product.product')
@@ -411,10 +411,10 @@ class Ecommerce(http.Controller):
}
return request.website.render("website_sale.mycart", values)
- @website.route(['/shop//add_cart/', '/shop/add_cart/'], type='http', auth="public")
- def add_cart(self, path=None, product_id=None, order_line_id=None, remove=None):
+ @website.route(['/shop//add_cart/', '/shop/add_cart/'], type='http', auth="public", multilang=True)
+ def add_cart(self, path=None, product_id=None, order_line_id=None, remove=None, **kw):
self.add_product_to_cart(product_id=product_id, order_line_id=order_line_id, number=(remove and -1 or 1))
- return werkzeug.utils.redirect("/shop/mycart/")
+ return request.redirect("/shop/mycart/")
@website.route(['/shop/add_cart_json/'], type='json', auth="public")
def add_cart_json(self, product_id=None, order_line_id=None, remove=None):
@@ -424,7 +424,7 @@ class Ecommerce(http.Controller):
def set_cart_json(self, path=None, product_id=None, order_line_id=None, set_number=0, json=None):
return self.add_product_to_cart(product_id=product_id, order_line_id=order_line_id, set_number=set_number)
- @website.route(['/shop/checkout/'], type='http', auth="public")
+ @website.route(['/shop/checkout/'], type='http', auth="public", multilang=True)
def checkout(self, **post):
classic_fields = ["name", "phone", "fax", "email", "street", "city", "state_id", "zip"]
rel_fields = ['country_id', 'state_id']
@@ -465,7 +465,7 @@ class Ecommerce(http.Controller):
return request.website.render("website_sale.checkout", values)
- @website.route(['/shop/confirm_order/'], type='http', auth="public")
+ @website.route(['/shop/confirm_order/'], type='http', auth="public", multilang=True)
def confirm_order(self, **post):
order = get_current_order()
@@ -474,10 +474,10 @@ class Ecommerce(http.Controller):
user_obj = request.registry.get('res.users')
if order.state != 'draft':
- return werkzeug.utils.redirect("/shop/checkout/")
+ return request.redirect("/shop/checkout/")
if not order.order_line:
error.append("empty_cart")
- return werkzeug.utils.redirect("/shop/checkout/")
+ return request.redirect("/shop/checkout/")
# check values
request.session['checkout'] = post
@@ -488,7 +488,7 @@ class Ecommerce(http.Controller):
if post.get('shipping_different') and key != 'email' and not post.get("shipping_%s" % key):
error.append("shipping_%s" % key)
if error:
- return werkzeug.utils.redirect("/shop/checkout/?error=%s&shipping=%s" % (",".join(error), post.get('shipping_different') and 'on' or ''))
+ return request.redirect("/shop/checkout/?error=%s&shipping=%s" % (",".join(error), post.get('shipping_different') and 'on' or ''))
# search or create company
company_id = None
@@ -548,9 +548,9 @@ class Ecommerce(http.Controller):
order_value.update(request.registry.get('sale.order').onchange_partner_id(request.cr, SUPERUSER_ID, [], order.partner_id.id, context=request.context)['value'])
order.write(order_value)
- return werkzeug.utils.redirect("/shop/payment/")
+ return request.redirect("/shop/payment/")
- @website.route(['/shop/payment/'], type='http', auth="public")
+ @website.route(['/shop/payment/'], type='http', auth="public", multilang=True)
def payment(self, **post):
order = get_current_order()
@@ -571,11 +571,11 @@ class Ecommerce(http.Controller):
return request.website.render("website_sale.payment", values)
- @website.route(['/shop/payment_validate/'], type='http', auth="public")
+ @website.route(['/shop/payment_validate/'], type='http', auth="public", multilang=True)
def payment_validate(self, **post):
request.httprequest.session['ecommerce_order_id'] = False
request.httprequest.session['ecommerce_pricelist'] = False
- return werkzeug.utils.redirect("/shop/")
+ return request.redirect("/shop/")
@website.route(['/shop/change_sequence/'], type='json', auth="public")
def change_sequence(self, id, top):
diff --git a/addons/website_sale/views/website_sale.xml b/addons/website_sale/views/website_sale.xml
index 8c124bd2728..ea4e43e1187 100644
--- a/addons/website_sale/views/website_sale.xml
+++ b/addons/website_sale/views/website_sale.xml
@@ -45,9 +45,9 @@