[REN] Renamed the state field access key names
[odoo/odoo.git] / addons / base_gengo / wizard / gengo_update_translation.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Business Applications
5 #    Copyright (C) 2004-2012 OpenERP S.A. (<http://openerp.com>).
6 #
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.
11 #
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.
16 #
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/>.
19 #
20 ##############################################################################
21
22 from osv import osv
23 from tools.translate import _
24 import re
25 try:
26     from mygengo import MyGengo
27 except ImportError:
28     raise osv.except_osv(_('Gengo ImportError'), _('Please install mygengo lib from http://pypi.python.org/pypi/mygengo'))
29
30 import logging
31 import tools
32 import time
33
34 _logger = logging.getLogger(__name__)
35
36 LIMIT = 20
37
38 LANG_CODE_MAPPING = {
39     'ar_SA': ('ar', 'Arabic'),
40     'id_ID': ('id', 'Indonesian'),
41     'nl_NL': ('nl', 'Dutch'),
42     'fr_CA': ('fr-ca', 'French (Canada)'),
43     'pl_PL': ('pl', 'Polish'),
44     'zh_TW': ('zh-tw', 'Chinese (Traditional)'),
45     'sv_SE': ('sv', 'Swedish'),
46     'ko_KR': ('ko', 'Korean'),
47     'pt_PT': ('pt', 'Portuguese (Europe)'),
48     'en_US': ('en', 'English'),
49     'ja_JP': ('ja', 'Japanese'),
50     'es_ES': ('es', 'Spanish (Spain)'),
51     'zh_CN': ('zh', 'Chinese (Simplified)'),
52     'de_DE': ('de', 'German'),
53     'fr_FR': ('fr', 'French'),
54     'fr_BE': ('fr', 'French'),
55     'ru_RU': ('ru', 'Russian'),
56     'it_IT': ('it', 'Italian'),
57     'pt_BR': ('pt-br', 'Portuguese (Brazil)')
58 }
59
60 CRON_VALS = {
61     'name': 'Gengo Sync',
62     'active': True,
63     'interval_number': 30,
64     'interval_type': 'minutes',
65     'numbercall': -1,
66     'model': "'base.update.translations'",
67     'function': ""
68 }
69
70
71 class base_update_translation(osv.osv_memory):
72
73     _name = 'base.update.translations'
74     _inherit = "base.update.translations"
75
76     def gengo_authentication(self, cr, uid, context=None):
77         ''' To Send Request and Get Response from Gengo User needs Public and Private
78          key for that user need to sign up to gengo and get public and private
79          key which is provided by gengo to authentic user '''
80
81         user = self.pool.get('res.users').browse(cr, uid, uid, context)
82         if not user.company_id.gengo_public_key or not user.company_id.gengo_private_key:
83             return (False, "  - Invalid gengo configuration, Either Gengo authentication `Public Key` or `Private Key` is missing. Complete Gengo authentication parameter under `Settings > Companies > Gengo Parameters`.")
84         try:
85             gengo = MyGengo(
86                 public_key=user.company_id.gengo_public_key.encode('ascii'),
87                 private_key=user.company_id.gengo_private_key.encode('ascii'),
88                 sandbox=True,
89             )
90             gengo.getAccountStats()
91             return (True, gengo)
92         except Exception, e:
93             return (False, "Gengo Connection Error\n%s"%e)
94
95     def pack_jobs_request(self, cr, uid, term_ids, context):
96         jobs = {}
97         gengo_parameter_pool = self.pool.get('res.users').browse(cr, uid, uid, context)
98         translation_pool = self.pool.get('ir.translation')
99         auto_approve = gengo_parameter_pool.company_id.gengo_auto_approve and 1 or 0
100         for term in translation_pool.browse(cr, uid, term_ids, context):
101             if re.search(r"\w", term.src or ""):
102                 job = {'type': 'text',
103                         'slug': 'single::English to ' + LANG_CODE_MAPPING[term.lang][1],
104                         'tier': tools.ustr(gengo_parameter_pool.company_id.gengo_tier),
105                         'body_src': term.src,
106                         'lc_src': 'en',
107                         'lc_tgt': LANG_CODE_MAPPING[term.lang][0],
108                         'auto_approve': auto_approve,
109                         'comment': gengo_parameter_pool.company_id.gengo_comment}
110                 jobs.update({term.id: job})
111         return {'jobs': jobs}
112
113     def check_lang_support(self, cr, uid, langs, context=None):
114         new_langs = []
115         flag, gengo = self.gengo_authentication(cr, uid, context)
116         if not flag:
117             return []
118         else:
119             user = self.pool.get('res.users').browse(cr, uid, uid, context)
120             tier = user.company_id.gengo_tier
121             if tier == "machine":
122                 tier = "nonprofit"
123             lang_pair = gengo.getServiceLanguagePairs(lc_src='en')
124             if lang_pair['opstat'] == 'ok':
125                 for g_lang in lang_pair['response']:
126                     for l in langs:
127                         if LANG_CODE_MAPPING[l][0] == g_lang['lc_tgt'] and g_lang['tier'] == tier:
128                             new_langs.append(l)
129             return list(set(new_langs))
130
131     def _update_terms(self, cr, uid, ids, response, tier, context):
132         translation_pool = self.pool.get('ir.translation')
133         for jobs in response['jobs']:        
134             for t_id, res in jobs.items():
135                 vals = {}
136                 if tier == "machine":
137                     vals.update({'value': res['body_tgt'], 'state': 'translated'})
138                 else:
139                     vals.update({'job_id': res['job_id'], 'state': 'inprogress'})
140                 translation_pool.write(cr, uid, [t_id], vals, context)
141         return
142
143     def _send_translation_terms(self, cr, uid, ids, term_ids, context):
144         """
145         Lazy Polling will be perform when user or cron request for the translation.
146         """
147         user = self.pool.get('res.users').browse(cr, uid, uid, context)
148         flag, gengo = self.gengo_authentication(cr, uid, context)
149         if flag:
150             request = self.pack_jobs_request(cr, uid, term_ids, context)
151             if request['jobs']:
152                 result = gengo.postTranslationJobs(jobs=request)
153                 if result['opstat'] == 'ok':
154                     self._update_terms(cr, uid, ids, result['response'], user.company_id.gengo_tier, context)
155         else:
156             _logger.error(gengo)
157         return True
158
159     def do_check_schedular(self, cr, uid, xml_id, name, fn, context=None):
160         cron_pool = self.pool.get('ir.cron')
161         try:
162             res = []
163             model, res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base_gengo', xml_id)
164             cron_pool.write(cr, uid, [res], {'active': True}, context=context)
165         except:
166             CRON_VALS.update({'name': name, "function": fn})
167             return cron_pool.create(cr, uid, CRON_VALS, context)
168
169     def act_update(self, cr, uid, ids, context=None):
170         if context == None:
171             context = {}
172         lang_pool = self.pool.get('res.lang')
173         super(base_update_translation, self).act_update(cr, uid, ids, context)
174         msg = "1. Translation file loaded successfully.\n2. Processing Gengo Translation:\n"
175         flag, gengo = self.gengo_authentication(cr, uid, context)
176         if not flag:
177             msg += gengo
178         else:
179             for res in self.browse(cr, uid, ids, context):
180                 lang_id = lang_pool.search(cr, uid, [('code', '=', res.lang)])
181                 lang_name = self._get_lang_name(cr, uid, res.lang)
182                 try:
183                     if LANG_CODE_MAPPING[res.lang][0]:
184                         lang_search = lang_pool.search(cr, uid, [('gengo_sync', '=', True), ('id', '=', lang_id[0])])
185                     if lang_search:
186                         msg += '  - This language `%s` is already in queue for translation.' % (lang_name)
187                     else:
188                         msg += '  - The language `%s` is queued for translation through Gengo translation.' % (lang_name)
189                         lang_pool.write(cr, uid, lang_id, {'gengo_sync': True})
190                         _logger.info('Translation request for language `%s` has been queued successfully.', lang_name)
191                     self.do_check_schedular(cr, uid, 'gengo_sync_send_request_scheduler', 'Gengo Sync Translation (Request)', '_sync_request', context)
192                     self.do_check_schedular(cr, uid, 'gengo_sync_receive_request_scheduler', 'Gengo Sync Translation (Response)', '_sync_response', context)
193                     self._sync_request(cr, uid, ids, context)
194                 except:
195                     msg +='  - The Language `%s` is not supported by Gengo Traditional Service.'%(lang_name)
196
197         context.update({'message': msg})
198         obj_model = self.pool.get('ir.model.data')
199         model_data_ids = obj_model.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'update_translation_wizard_view_confirm')])
200         view_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
201         return {
202                  'view_type': 'form',
203                  'view_mode': 'form',
204                  'res_model': 'gengo.update.message',
205                  'views': [(view_id, 'form')],
206                  'type': 'ir.actions.act_window',
207                  'target': 'new',
208                  'context': context,
209              }
210
211     def _sync_response(self, cr, uid, ids=False, context=None):
212         """
213         This method  will be call by cron services to get translation from
214         gengo for translation terms which are posted to be translated. It will
215         read translated terms and comments from gengo and will update respective
216         translation in openerp """
217         translation_pool = self.pool.get('ir.translation')
218         flag, gengo = self.gengo_authentication(cr, uid, context)
219         if not flag:
220             _logger.warning("%s", gengo)
221         else:
222             translation_id = translation_pool.search(cr, uid, [('state', '=', 'inprogress'), ('gengo_translation', '=', True)], limit=LIMIT, context=context)
223             for term in translation_pool.browse(cr, uid, translation_id, context):
224                 if term.job_id:
225                     vals={}
226                     job_response = gengo.getTranslationJob(id=term.job_id)
227                     if job_response['opstat'] != 'ok':
228                         _logger.warning("Invalid Response! Skipping translation Terms with `id` %s."%(term.job_id))
229                         continue
230                     if job_response['response']['job']['status'] == 'approved':
231                         vals.update({'state': 'translated',
232                             'value': job_response['response']['job']['body_tgt'],
233                             'gengo_control': True})
234                     job_comment = gengo.getTranslationJobComments(id=term.job_id)
235                     if job_comment['opstat']=='ok':
236                         gengo_comments=""
237                         for comment in job_comment['response']['thread']:
238                             gengo_comments+='%s by %s at %s. \n'    %(comment['body'],comment['author'],time.ctime(comment['ctime']))
239                         vals.update({'gengo_comment':gengo_comments})
240                     if vals:
241                         translation_pool.write(cr, uid, term.id,vals)
242         return True
243
244     def _sync_request(self, cr, uid, ids=False, context=None):
245         """This scheduler will send a job request to the gengo , which terms are
246         in translate state and gengo_translation is true"""
247         if context is None:
248             context = {}
249         language_pool = self.pool.get('res.lang')
250         translation_pool = self.pool.get('ir.translation')
251         try:
252             lang_ids = language_pool.search(cr, uid, [('gengo_sync', '=', True)])
253             langs = [lang.code for lang in language_pool.browse(cr, uid, lang_ids)]
254             langs = self.check_lang_support(cr, uid, langs)
255             term_ids = translation_pool.search(cr, uid, [('state', '=', 'to_translate'), ('gengo_translation', '=', True), ('lang', 'in', langs)], limit=LIMIT)
256             if term_ids:
257                 self._send_translation_terms(cr, uid, ids, term_ids, context)
258                 _logger.info("Translation terms %s has been posted to gengo successfully", len(term_ids))
259             else:
260                 _logger.info('No Translation terms to process.')
261         except Exception, e:
262             _logger.error("%s", e)
263
264 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: