From 366843b0020ce4296b60d38ff3cc6a2344ce1bf8 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Mon, 23 Sep 2013 13:50:54 +0200
Subject: [PATCH 01/40] [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/40] [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/40] [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/40] [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/40] [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/40] [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 aae0a815d2d087ef0ce2b16311268ab30a6a64a4 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Wed, 25 Sep 2013 13:28:03 +0200
Subject: [PATCH 13/40] [IMP] replace instances of t[@t-field], they're a pain
in the ass
bzr revid: xmo@openerp.com-20130925112803-ya54yb2kwdodj3y5
---
addons/website/views/views.xml | 2 +-
addons/website_blog/views/website_blog_templates.xml | 12 ++++++------
addons/website_event/views/website_event.xml | 2 +-
addons/website_sale/views/website_sale.xml | 8 ++++----
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/addons/website/views/views.xml b/addons/website/views/views.xml
index f550234949e..58967b3e042 100644
--- a/addons/website/views/views.xml
+++ b/addons/website/views/views.xml
@@ -77,7 +77,7 @@
@@ -180,7 +180,7 @@
-
+
diff --git a/addons/website_event/views/website_event.xml b/addons/website_event/views/website_event.xml
index 4f01417daeb..012cb7ff36c 100644
--- a/addons/website_event/views/website_event.xml
+++ b/addons/website_event/views/website_event.xml
@@ -180,7 +180,7 @@
|
|
|
- / |
+ / |
|