1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Business Applications
5 # Copyright (C) 2004-2012 OpenERP S.A. (<http://openerp.com>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
26 from openerp.osv import osv, fields
27 from openerp import tools
28 from openerp.tools.translate import _
30 _logger = logging.getLogger(__name__)
33 from gengo import Gengo
35 _logger.warning('Gengo library not found, Gengo features disabled. If you plan to use it, please install the gengo library from http://pypi.python.org/pypi/gengo')
37 GENGO_DEFAULT_LIMIT = 20
39 class base_gengo_translations(osv.osv_memory):
41 _name = 'base.gengo.translations'
43 'sync_type': fields.selection([('send', 'Send New Terms'),
44 ('receive', 'Receive Translation'),
45 ('both', 'Both')], "Sync Type"),
46 'lang_id': fields.many2one('res.lang', 'Language', required=True),
47 'sync_limit': fields.integer("No. of terms to sync"),
49 _defaults = {'sync_type' : 'both',
52 def gengo_authentication(self, cr, uid, context=None):
54 This method tries to open a connection with Gengo. For that, it uses the Public and Private
55 keys that are linked to the company (given by Gengo on subscription). It returns a tuple with
56 * as first element: a boolean depicting if the authentication was a success or not
57 * as second element: the connection, if it was a success, or the error message returned by
58 Gengo when the connection failed.
59 This error message can either be displayed in the server logs (if the authentication was called
60 by the cron) or in a dialog box (if requested by the user), thus it's important to return it
63 user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
64 if not user.company_id.gengo_public_key or not user.company_id.gengo_private_key:
65 return (False, _("Gengo `Public Key` or `Private Key` are missing. Enter your Gengo authentication parameters under `Settings > Companies > Gengo Parameters`."))
68 public_key=user.company_id.gengo_public_key.encode('ascii'),
69 private_key=user.company_id.gengo_private_key.encode('ascii'),
70 sandbox=user.company_id.gengo_sandbox,
72 gengo.getAccountStats()
75 _logger.exception('Gengo connection failed')
76 return (False, _("Gengo connection failed with this message:\n``%s``") % e)
78 def act_update(self, cr, uid, ids, context=None):
80 Function called by the wizard.
85 flag, gengo = self.gengo_authentication(cr, uid, context=context)
87 raise osv.except_osv(_('Gengo Authentication Error'), gengo)
88 for wizard in self.browse(cr, uid, ids, context=context):
89 supported_langs = self.pool.get('ir.translation')._get_all_supported_languages(cr, uid, context=context)
90 language = self.pool.get('ir.translation')._get_gengo_corresponding_language(wizard.lang_id.code)
91 if language not in supported_langs:
92 raise osv.except_osv(_("Warning"), _('This language is not supported by the Gengo translation services.'))
95 ctx['gengo_language'] = wizard.lang_id.id
96 if wizard.sync_limit > 200 or wizard.sync_limit < 1:
97 raise osv.except_osv(_("Warning"), _('Sync limit should between 1 to 200 for Gengo translation services.'))
98 if wizard.sync_type in ['send', 'both']:
99 self._sync_request(cr, uid, wizard.sync_limit, context=ctx)
100 if wizard.sync_type in ['receive', 'both']:
101 self._sync_response(cr, uid, wizard.sync_limit, context=ctx)
102 return {'type': 'ir.actions.act_window_close'}
104 def _sync_response(self, cr, uid, limit=GENGO_DEFAULT_LIMIT, context=None):
106 This method will be called by cron services to get translations from
107 Gengo. It will read translated terms and comments from Gengo and will
108 update respective ir.translation in openerp.
110 translation_pool = self.pool.get('ir.translation')
111 flag, gengo = self.gengo_authentication(cr, uid, context=context)
113 _logger.warning("%s", gengo)
116 all_translation_ids = translation_pool.search(cr, uid, [('state', '=', 'inprogress'), ('gengo_translation', 'in', ('machine', 'standard', 'pro', 'ultra')), ('job_id', "!=", False)], context=context)
118 translation_ids = all_translation_ids[offset:offset + limit]
120 if not translation_ids:
122 translation_terms = translation_pool.browse(cr, uid, translation_ids, context=context)
123 gengo_job_id = [term.job_id for term in translation_terms]
125 gengo_ids = ','.join(gengo_job_id)
127 job_response = gengo.getTranslationJobBatch(id=gengo_ids)
130 if job_response['opstat'] == 'ok':
131 for job in job_response['response'].get('jobs', []):
132 self._update_terms_job(cr, uid, job, context=context)
135 def _update_terms_job(self, cr, uid, job, context=None):
136 translation_pool = self.pool.get('ir.translation')
137 tid = int(job['custom_data'])
139 if job.get('job_id', False):
140 vals['job_id'] = job['job_id']
141 vals['state'] = 'inprogress'
142 if job.get('status', False) in ('queued','available','pending','reviewable'):
143 vals['state'] = 'inprogress'
144 if job.get('body_tgt', False) and job.get('status', False)=='approved':
145 vals['value'] = job['body_tgt']
146 if job.get('status', False) in ('approved', 'canceled'):
147 vals['state'] = 'translated'
149 translation_pool.write(cr, uid, [tid], vals, context=context)
151 def _update_terms(self, cr, uid, response, context=None):
153 Update the terms after their translation were requested to Gengo
155 for jobs in response.get('jobs', []):
156 for t_id, res in jobs.items():
157 self._update_terms_job(cr, uid, res, context=context)
160 def pack_jobs_request(self, cr, uid, term_ids, context=None):
161 ''' prepare the terms that will be requested to gengo and returns them in a dictionary with following format
168 translation_pool = self.pool.get('ir.translation')
170 user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
171 auto_approve = 1 if user.company_id.gengo_auto_approve else 0
172 for term in translation_pool.browse(cr, uid, term_ids, context=context):
173 if re.search(r"\w", term.src or ""):
174 comment = user.company_id.gengo_comment or ''
175 if term.gengo_comment:
176 comment+='\n' + term.gengo_comment
177 jobs[time.strftime('%Y%m%d%H%M%S') + '-' + str(term.id)] = {
179 'slug': 'Single :: English to ' + term.lang,
180 'tier': tools.ustr(term.gengo_translation),
181 'custom_data': str(term.id),
182 'body_src': term.src,
184 'lc_tgt': translation_pool._get_gengo_corresponding_language(term.lang),
185 'auto_approve': auto_approve,
187 'callback_url': self.pool.get('ir.config_parameter').get_param(cr, uid,'web.base.url') + '/website/gengo_callback'
189 return {'jobs': jobs, 'as_group': 1}
192 def _send_translation_terms(self, cr, uid, term_ids, context=None):
194 Send a request to Gengo with all the term_ids in a different job, get the response and update the terms in
195 database accordingly.
197 flag, gengo = self.gengo_authentication(cr, uid, context=context)
199 request = self.pack_jobs_request(cr, uid, term_ids, context=context)
201 result = gengo.postTranslationJobs(jobs=request)
202 if result['opstat'] == 'ok':
203 self._update_terms(cr, uid, result['response'], context=context)
208 def _sync_request(self, cr, uid, limit=GENGO_DEFAULT_LIMIT, context=None):
210 This scheduler will send a job request to the gengo , which terms are
211 waiing to be translated and for which gengo_translation is enabled.
213 A special key 'gengo_language' can be passed in the context in order to
214 request only translations of that language only. Its value is the language
219 language_pool = self.pool.get('res.lang')
220 translation_pool = self.pool.get('ir.translation')
221 domain = [('state', '=', 'to_translate'), ('gengo_translation', 'in', ('machine', 'standard', 'pro', 'ultra')), ('job_id', "=", False)]
222 if context.get('gengo_language', False):
223 lc = language_pool.browse(cr, uid, context['gengo_language'], context=context).code
224 domain.append( ('lang', '=', lc) )
226 all_term_ids = translation_pool.search(cr, uid, domain, context=context)
230 #search for the n first terms to translate
231 term_ids = all_term_ids[offset:offset + limit]
234 self._send_translation_terms(cr, uid, term_ids, context=context)
235 _logger.info("%s Translation terms have been posted to Gengo successfully", len(term_ids))
236 if not len(term_ids) == limit:
239 _logger.error("%s", e)
241 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: