diff --git a/web_translate_dialog/README.rst b/web_translate_dialog/README.rst index 00a5ceaf..10d92814 100644 --- a/web_translate_dialog/README.rst +++ b/web_translate_dialog/README.rst @@ -1,7 +1,15 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +==================== Web Translate Dialog ==================== -This module replaces the standard translation view by an easy-to-use pop-up view where you can translate all the fields of the object in all the installed languages (for long-time users, it may remind them the translation pop-up of OpenERP 6.1). +This module replaces the standard translation view by an easy-to-use pop-up +view where you can translate all the fields of the object in all the installed +languages (for long-time users, it may remind them the translation pop-up of +OpenERP 6.1). This module also features: @@ -12,25 +20,53 @@ This module also features: Usage ===== -Go to an object that has translatable fields (*Products* for example) and select *More > Translate* (or click on *Edit* and then click on the flag at the top-right of one of the translatable fields): the translation view will pop-up on your screen. This translation view contains all the translatable fields of the object. +Go to an object that has translatable fields (*Products* for example) and +select *More > Translate* (or click on *Edit* and then click on the flag at +the top-right of one of the translatable fields): the translation view will +pop-up on your screen. This translation view contains all the translatable +fields of the object. + +If you click in the standard translate icon then the translation view will +pop-up with this field only. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/162/9.0 + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. Credits ======= +Images +------ + +* Odoo Community Association: `Icon `_. + Contributors ------------ * Guewen Baconnier (Camptocamp) +* Antonio Espinosa Maintainer ---------- -.. image:: http://odoo-community.org/logo.png +.. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association - :target: http://odoo-community.org + :target: https://odoo-community.org This module is maintained by the OCA. -OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. -To contribute to this module, please visit http://odoo-community.org. +To contribute to this module, please visit https://odoo-community.org. diff --git a/web_translate_dialog/__openerp__.py b/web_translate_dialog/__openerp__.py index 2656bd36..7dd28159 100644 --- a/web_translate_dialog/__openerp__.py +++ b/web_translate_dialog/__openerp__.py @@ -1,32 +1,26 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Author: Guewen Baconnier -# Copyright 2012 Camptocamp SA -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -{"name": "Web Translate Dialog", - "category": "Web", - "summary": "Easy-to-use pop-up to translate fields in several languages", - "license": "AGPL-3", - "author": "Camptocamp,Odoo Community Association (OCA)", - "version": "8.0.1.0.0", - "depends": ['web'], - 'data': ['view/web_translate.xml'], - 'qweb': ["static/src/xml/base.xml"], - 'installable': False, - } +# Copyright 2012 Guewen Baconnier (Camptocamp SA) +# Copyright 2016 Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Web Translate Dialog", + "summary": "Easy-to-use pop-up to translate fields in several languages", + "version": "9.0.1.0.0", + "category": "Web", + "website": "https://odoo-community.org/", + "author": "Camptocamp, " + "Tecnativa, " + "Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "web", + ], + "data": [ + "view/web_translate.xml", + ], + "qweb": [ + "static/src/xml/base.xml", + ] +} diff --git a/web_translate_dialog/static/src/css/base.css b/web_translate_dialog/static/src/css/base.css index 8f884849..aec33758 100644 --- a/web_translate_dialog/static/src/css/base.css +++ b/web_translate_dialog/static/src/css/base.css @@ -1,3 +1,6 @@ +/* Copyright 2012 Guewen Baconnier (Camptocamp SA) + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + .openerp .oe_translation_field { width: 95%; } diff --git a/web_translate_dialog/static/src/js/web_translate_dialog.js b/web_translate_dialog/static/src/js/web_translate_dialog.js index 89c284c1..cbce9f5e 100644 --- a/web_translate_dialog/static/src/js/web_translate_dialog.js +++ b/web_translate_dialog/static/src/js/web_translate_dialog.js @@ -1,209 +1,228 @@ -openerp.web_translate_dialog = function (instance) { +/* Copyright 2012 Guewen Baconnier (Camptocamp SA) + Copyright 2016 Antonio Espinosa + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ - "use strict"; +odoo.define('web_translate_dialog.translate_dialog', function(require){ +"use strict"; - var QWeb = instance.web.qweb, - _t = instance.web._t, - _lt = instance.web._lt; +var _ = require('_'); +var $ = require('$'); - instance.web.FormView.include({ - load_form: function(data) { - var self = this; - this._super(data); - if (this.sidebar) { - this.sidebar.add_items('other', _.compact([ - self.is_action_enabled('edit') && { label: _t('Translate'), callback: self.on_button_translate }, - ])); - } - }, - on_button_translate: function() { - var self = this; - $.when(this.has_been_loaded).then(function() { - self.open_translate_dialog(this); - }); - }, - }); +var core = require('web.core'); +var data = require('web.data'); +var common = require('web.form_common'); - instance.web.View.include({ - open_translate_dialog: function() { - new instance.web_translate_dialog.TranslateDialog(this).open(); - } - }); +var FormView = require('web.FormView'); +var View = require('web.View'); +var Dialog = require('web.Dialog'); - instance.web_translate_dialog.TranslateDialog = instance.web.Dialog.extend({ - template: "TranslateDialog", - init: function(parent, options, content) { - this._super(parent, - {title: _t("Translations"), - width: '90%', - height: '80%'}, - content); - this.view_language = this.session.user_context.lang; - this.view = parent; - this.view_type = parent.fields_view.type || ''; - this.$view_form = null; - this.$sidebar_form = null; - this.translatable_fields_keys = _.map(this.view.translatable_fields || [], function(i) { return i.name;}); - this.languages = null; - this.languages_loaded = $.Deferred(); - (new instance.web.DataSetSearch(this, - 'res.lang', - this.view.dataset.get_context(), - [['translatable', '=', '1']])) - .read_slice(['code', 'name'], { sort: 'id' }) - .then(this.on_languages_loaded); - }, - on_languages_loaded: function(langs) { - this.languages = langs; - this.languages_loaded.resolve(); - }, - open: function() { - var self = this, - sup = this._super; - // the template needs the languages - $.when(this.languages_loaded).then(function() { - return sup.call(self); - }); - }, - start: function() { - var self = this; - this.$el.find('.oe_translation_field').change(function() { - $(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value'))); - }); - this.$buttons.html(QWeb.render("TranslateDialog.buttons")); - this.$buttons.find(".oe_form_translate_dialog_save_button").click(function(){ - self.on_button_save(); - self.on_button_close(); - }); - this.$buttons.find(".oe_form_translate_dialog_cancel_button").click(function(){ - self.on_button_close(); - }); - this.initialize_html_fields(); +var _t = core._t; +var QWeb = core.qweb; - this.do_load_fields_values(); - }, - initialize_html_fields: function() { - this.$el.find('.oe_form_field_html textarea').each(function() { - var $textarea = $(this); - var width = 100; // forced to fixed size on initialization - // will be changed to percentage right after - // the creation - var height = 250; - $textarea.cleditor({ - width: width, // width not including margins, borders or padding - height: height, // height not including margins, borders or padding - controls: // controls to add to the toolbar - "bold italic underline strikethrough " + - "| removeformat | bullets numbering | outdent " + - "indent | link unlink | source", - bodyStyle: // style to assign to document body contained within the editor - "margin:4px; color:#4c4c4c; font-size:13px; font-family:'Lucida Grande',Helvetica,Verdana,Arial,sans-serif; cursor:text" - }); +var translateDialog = Dialog.extend({ + template: "TranslateDialog", + init: function(parent, field, content) { + this._super(parent, + {title: _t("Translations"), + width: '90%', + height: '80%'}, + content); + this.view_language = this.session.user_context.lang; + this.view = parent; + this.view_type = parent.fields_view.type || ''; + this.$view_form = null; + this.$sidebar_form = null; + if (!!field) { + this.translatable_fields_keys = [field]; + this.translatable_fields = _.filter( + this.view.translatable_fields || [], + function(i) {return i.name == field;} + ); + } else { + this.translatable_fields_keys = _.map( + this.view.translatable_fields || [], + function(i) {return i.name;} + ); + this.translatable_fields = this.view.translatable_fields.slice(0); + } + this.languages = null; + this.languages_loaded = $.Deferred(); + (new data.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(), + [['translatable', '=', '1']])) + .read_slice(['code', 'name'], { sort: 'id' }) + .then(this.on_languages_loaded); + }, + on_languages_loaded: function(langs) { + this.languages = langs; + this.languages_loaded.resolve(); + }, + open: function() { + var self = this, + sup = this._super; + // the template needs the languages + $.when(this.languages_loaded).then(function() { + return sup.call(self); + }); + }, + start: function() { + var self = this; + this.$el.find('.oe_translation_field').change(function() { + $(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value'))); + }); + this.$footer.html(QWeb.render("TranslateDialog.buttons")); + this.$footer.find(".oe_form_translate_dialog_save_button").click(function(){ + self.on_button_save(); + self.on_button_close(); + }); + this.$footer.find(".oe_form_translate_dialog_cancel_button").click(function(){ + self.on_button_close(); + }); - var $cleditor = $textarea.cleditor()[0]; - // Down to -- end, this is a workaround for the bug - // https://bugs.launchpad.net/openerp-web/+bug/1258463 - // The editor is initially created with a fixed size so - // the buggy event is not bound to $(window), then we restore - // a percentage width and bind the "normal" event without the - // CHM's buggy change. - $cleditor.$main.width('95%'); - $cleditor.options.width = '95%'; - $(window).resize(function() { - //Forcefully blurred iframe contentWindow, chrome, IE, safari doesn't trigger blur on window resize and due to which text disappears - var contentWindow = $cleditor.$frame[0].contentWindow; - if(!$.browser.mozilla && contentWindow){ - $(contentWindow).trigger('blur'); + this.do_load_fields_values(); + }, + initialize_html_fields: function(lang) { + var self = this; + _.each(this.translatable_fields_keys, function(f) { + // Initialize summernote if HTML field + self.$el.find('.oe_form_field_html .oe_translation_field[name="' + lang.code + '-' + f + '"]').each(function() { + var $parent = $(this).summernote({ + 'focus': false, + 'toolbar': [ + ['style', ['style']], + ['font', ['bold', 'italic', 'underline', 'clear']], + ['fontsize', ['fontsize']], + ['color', ['color']], + ['para', ['ul', 'ol', 'paragraph']], + ['table', ['table']], + ['insert', ['link', 'picture']], + ['history', ['undo', 'redo']] + ], + 'prettifyHtml': false, + 'styleWithSpan': false, + 'inlinemedia': ['p'], + 'lang': "odoo", + 'onChange': function (value) { + $(this).toggleClass('touched', (value != $(this).attr('data-value'))); } + }).parent(); + // Triggers a mouseup to refresh the editor toolbar + $parent.find('.note-editable').trigger('mouseup'); + $parent.find('.note-editing-area').css({ + minHeight:'100px', + minWidth:'260px', }); - $cleditor.refresh(); - // -- end + }); + }); + }, + set_fields_values: function(lang, values) { + var self = this; + _.each(this.translatable_fields_keys, function(f) { + self.$el.find('.oe_translation_field[name="' + lang.code + '-' + f + '"]') + .val(values[f] || '') + .attr('data-value', values[f] || ''); + }); + this.$el.find('textarea.oe_translation_field').css({ + minHeight:'100px', + }); + $(window).resize(); // triggers the autosize + this.initialize_html_fields(lang); + }, + do_load_fields_values: function() { + var self = this, + deferred = []; - $cleditor.change(function() { - this.updateTextArea(); - this.$area.toggleClass('touched', - (this.$area.val() != this.$area.attr('data-value'))); + this.$el.find('.oe_translation_field').val('').removeClass('touched'); + _.each(self.languages, function(lg) { + var deff = $.Deferred(); + deferred.push(deff); + if (lg.code === self.view_language) { + var values = {}; + _.each(self.translatable_fields_keys, function(field) { + values[field] = self.view.fields[field].get_value(); }); + self.set_fields_values(lg, values); + deff.resolve(); + } else { + self.view.dataset.call( + 'read', + [[self.view.datarecord.id], + self.translatable_fields_keys, + self.view.dataset.get_context({ + 'lang': lg.code + })]).done(function (rows) { + self.set_fields_values(lg, rows[0]); + deff.resolve(); + }); + } + }); + return deferred; + }, + on_button_save: function() { + var translations = {}, + self = this, + translation_mutex = new $.Mutex(); + self.$el.find('.oe_translation_field.touched').each(function() { + var field = $(this).attr('name').split('-'); + if (!translations[field[0]]) { + translations[field[0]] = {}; + } + translations[field[0]][field[1]] = $(this).val(); + }); + _.each(translations, function(text, code) { + if (code === self.view_language) { + self.view.set_values(text); + } + translation_mutex.exec(function() { + return new data.DataSet(self, self.view.dataset.model, + self.view.dataset.get_context()) + .write(self.view.datarecord.id, text, + { context : { 'lang': code }}); }); - }, - set_fields_values: function(lang, values) { - var self = this; - _.each(this.translatable_fields_keys, function(f) { - self.$el.find('.oe_translation_field[name="' + lang.code + '-' + f + '"]') - .val(values[f] || '') - .attr('data-value', values[f] || ''); + }); + this.close(); + }, + on_button_close: function() { + this.close(); + }, - var $tarea = self.$el.find('.oe_form_field_html .oe_translation_field[name="' + lang.code + '-' + f + '"]'); - if ($tarea.length) { - $tarea.cleditor()[0].updateFrame(); - } - }); - var $textarea = this.$el.find('textarea.oe_translation_field'); - $textarea.css({minHeight:'100px'}); - $textarea.autosize(); - $(window).resize(); // triggers the autosize - }, - do_load_fields_values: function() { - var self = this, - deferred = []; +}); - this.$el.find('.oe_translation_field').val('').removeClass('touched'); - _.each(self.languages, function(lg) { - var deff = $.Deferred(); - deferred.push(deff); - if (lg.code === self.view_language) { - var values = {}; - _.each(self.translatable_fields_keys, function(field) { - values[field] = self.view.fields[field].get_value(); - }); - self.set_fields_values(lg, values); - deff.resolve(); - } else { - self.view.dataset.call( - 'read', - [[self.view.datarecord.id], - self.translatable_fields_keys, - self.view.dataset.get_context({ - 'lang': lg.code - })]).done(function (rows) { - self.set_fields_values(lg, rows[0]); - deff.resolve(); - }); - }; - }); - return deferred; - }, - on_button_save: function() { - var translations = {}, - self = this, - translation_mutex = new $.Mutex(); - self.$el.find('.oe_translation_field.touched').each(function() { - var field = $(this).attr('name').split('-'); - if (!translations[field[0]]) { - translations[field[0]] = {}; - } - translations[field[0]][field[1]] = $(this).val(); - }); - _.each(translations, function(data, code) { - if (code === self.view_language) { - self.view.set_values(data); - } - translation_mutex.exec(function() { - return new instance.web.DataSet(self, self.view.dataset.model, self.view.dataset.get_context()).write(self.view.datarecord.id, data, { context : { 'lang': code }}); - }); - }); - this.close(); - }, - on_button_close: function() { - this.close(); - }, +FormView.include({ + render_sidebar: function($node) { + this._super($node); + if (this.sidebar) { + this.sidebar.add_items('other', _.compact([ + this.is_action_enabled('edit') && + this.translatable_fields.length > 0 && { + label: _t('Translate'), + callback: this.on_button_translate + }, + ])); + } + }, + on_button_translate: function() { + var self = this; + $.when(this.has_been_loaded).then(function() { + self.open_translate_dialog(); + }); + }, +}); - }); +View.include({ + open_translate_dialog: function(field) { + new translateDialog(this, field).open(); + } +}); - instance.web.form.AbstractField.include({ - on_translate: function() { - // the image next to the fields opens the translate dialog - this.view.open_translate_dialog(); - }, - }); +common.AbstractField.include({ + on_translate: function() { + // the image next to the fields opens the translate dialog + this.view.open_translate_dialog(this.name); + }, +}); + +return { + translateDialog: translateDialog, }; + +}); // odoo.define diff --git a/web_translate_dialog/static/src/xml/base.xml b/web_translate_dialog/static/src/xml/base.xml index 689586b5..ae3ee5e2 100644 --- a/web_translate_dialog/static/src/xml/base.xml +++ b/web_translate_dialog/static/src/xml/base.xml @@ -1,34 +1,51 @@ - + + +