2012-08-17 06:27:30 +00:00
# -*- coding: utf-8 -*-
2012-08-06 07:40:35 +00:00
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (C) 2004-2012 OpenERP S.A. (<http://openerp.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
2014-06-20 15:33:09 +00:00
import uuid
2012-08-06 07:40:35 +00:00
import logging
2012-11-16 13:50:21 +00:00
import re
2012-08-27 10:54:13 +00:00
import time
2012-08-27 07:27:43 +00:00
2012-11-16 13:50:21 +00:00
from openerp . osv import osv , fields
2014-06-20 15:33:09 +00:00
from openerp import tools , SUPERUSER_ID
2012-11-16 13:50:21 +00:00
from openerp . tools . translate import _
2012-08-06 07:40:35 +00:00
_logger = logging . getLogger ( __name__ )
2012-08-27 09:40:27 +00:00
2012-11-16 13:50:21 +00:00
try :
2014-05-27 13:51:09 +00:00
from gengo import Gengo
2012-11-16 13:50:21 +00:00
except ImportError :
2014-05-27 13:51:09 +00:00
_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 ' )
2012-11-16 13:50:21 +00:00
2012-08-29 08:26:47 +00:00
GENGO_DEFAULT_LIMIT = 20
2014-06-20 15:33:09 +00:00
2012-08-30 16:14:29 +00:00
class base_gengo_translations ( osv . osv_memory ) :
2014-06-20 15:33:09 +00:00
GENGO_KEY = " Gengo.UUID "
2014-08-01 11:39:09 +00:00
GROUPS = [ ' base.group_system ' ]
2012-08-06 07:40:35 +00:00
2012-08-30 16:14:29 +00:00
_name = ' base.gengo.translations '
_columns = {
2014-03-21 07:14:38 +00:00
' sync_type ' : fields . selection ( [ ( ' send ' , ' Send New Terms ' ) ,
( ' receive ' , ' Receive Translation ' ) ,
( ' both ' , ' Both ' ) ] , " Sync Type " ) ,
2012-11-16 13:50:21 +00:00
' lang_id ' : fields . many2one ( ' res.lang ' , ' Language ' , required = True ) ,
2014-03-28 11:37:15 +00:00
' sync_limit ' : fields . integer ( " No. of terms to sync " ) ,
2012-08-30 16:14:29 +00:00
}
2014-06-20 15:33:09 +00:00
_defaults = {
' sync_type ' : ' both ' ,
' sync_limit ' : 20
}
def init ( self , cr ) :
icp = self . pool [ ' ir.config_parameter ' ]
if not icp . get_param ( cr , SUPERUSER_ID , self . GENGO_KEY , default = None ) :
2014-08-01 11:39:09 +00:00
icp . set_param ( cr , SUPERUSER_ID , self . GENGO_KEY , str ( uuid . uuid4 ( ) ) , groups = self . GROUPS )
2014-06-20 15:33:09 +00:00
def get_gengo_key ( self , cr ) :
icp = self . pool [ ' ir.config_parameter ' ]
return icp . get_param ( cr , SUPERUSER_ID , self . GENGO_KEY , default = " Undefined " )
2012-08-27 06:52:18 +00:00
def gengo_authentication ( self , cr , uid , context = None ) :
2014-05-27 13:51:09 +00:00
'''
2012-08-30 16:14:29 +00:00
This method tries to open a connection with Gengo . For that , it uses the Public and Private
keys that are linked to the company ( given by Gengo on subscription ) . It returns a tuple with
* as first element : a boolean depicting if the authentication was a success or not
2014-05-27 13:51:09 +00:00
* as second element : the connection , if it was a success , or the error message returned by
2012-08-30 16:14:29 +00:00
Gengo when the connection failed .
2014-05-27 13:51:09 +00:00
This error message can either be displayed in the server logs ( if the authentication was called
by the cron ) or in a dialog box ( if requested by the user ) , thus it ' s important to return it
2012-08-30 16:14:29 +00:00
translated .
'''
2014-09-03 09:55:00 +00:00
user = self . pool . get ( ' res.users ' ) . browse ( cr , 1 , uid , context = context )
2012-08-27 06:52:18 +00:00
if not user . company_id . gengo_public_key or not user . company_id . gengo_private_key :
2012-11-16 13:50:21 +00:00
return ( False , _ ( " Gengo `Public Key` or `Private Key` are missing. Enter your Gengo authentication parameters under `Settings > Companies > Gengo Parameters`. " ) )
2012-08-27 06:52:18 +00:00
try :
2014-05-27 13:51:09 +00:00
gengo = Gengo (
2012-08-27 06:52:18 +00:00
public_key = user . company_id . gengo_public_key . encode ( ' ascii ' ) ,
private_key = user . company_id . gengo_private_key . encode ( ' ascii ' ) ,
2014-04-03 15:17:46 +00:00
sandbox = user . company_id . gengo_sandbox ,
2012-08-27 06:52:18 +00:00
)
gengo . getAccountStats ( )
return ( True , gengo )
except Exception , e :
2012-11-16 13:50:21 +00:00
_logger . exception ( ' Gengo connection failed ' )
return ( False , _ ( " Gengo connection failed with this message: \n `` %s `` " ) % e )
2012-08-29 08:26:47 +00:00
2012-08-23 13:42:57 +00:00
def act_update ( self , cr , uid , ids , context = None ) :
2012-08-30 16:14:29 +00:00
'''
Function called by the wizard .
'''
2014-04-03 15:17:46 +00:00
if context is None :
2012-08-23 13:42:57 +00:00
context = { }
2012-08-24 13:21:25 +00:00
2012-08-30 16:14:29 +00:00
flag , gengo = self . gengo_authentication ( cr , uid , context = context )
if not flag :
raise osv . except_osv ( _ ( ' Gengo Authentication Error ' ) , gengo )
for wizard in self . browse ( cr , uid , ids , context = context ) :
supported_langs = self . pool . get ( ' ir.translation ' ) . _get_all_supported_languages ( cr , uid , context = context )
language = self . pool . get ( ' ir.translation ' ) . _get_gengo_corresponding_language ( wizard . lang_id . code )
if language not in supported_langs :
2012-11-16 13:50:21 +00:00
raise osv . except_osv ( _ ( " Warning " ) , _ ( ' This language is not supported by the Gengo translation services. ' ) )
2012-08-30 16:14:29 +00:00
ctx = context . copy ( )
ctx [ ' gengo_language ' ] = wizard . lang_id . id
2014-03-28 11:37:15 +00:00
if wizard . sync_limit > 200 or wizard . sync_limit < 1 :
raise osv . except_osv ( _ ( " Warning " ) , _ ( ' Sync limit should between 1 to 200 for Gengo translation services. ' ) )
2014-04-03 15:17:46 +00:00
if wizard . sync_type in [ ' send ' , ' both ' ] :
2014-03-28 11:37:15 +00:00
self . _sync_request ( cr , uid , wizard . sync_limit , context = ctx )
2014-04-03 15:17:46 +00:00
if wizard . sync_type in [ ' receive ' , ' both ' ] :
self . _sync_response ( cr , uid , wizard . sync_limit , context = ctx )
2012-08-30 16:14:29 +00:00
return { ' type ' : ' ir.actions.act_window_close ' }
2012-08-06 10:25:17 +00:00
2012-08-29 08:26:47 +00:00
def _sync_response ( self , cr , uid , limit = GENGO_DEFAULT_LIMIT , context = None ) :
2012-08-27 10:54:13 +00:00
"""
2012-08-30 16:14:29 +00:00
This method will be called by cron services to get translations from
2014-04-03 15:17:46 +00:00
Gengo . It will read translated terms and comments from Gengo and will
2014-07-09 11:39:38 +00:00
update respective ir . translation in Odoo .
2012-08-28 11:04:26 +00:00
"""
2012-08-06 10:25:17 +00:00
translation_pool = self . pool . get ( ' ir.translation ' )
2012-08-30 16:14:29 +00:00
flag , gengo = self . gengo_authentication ( cr , uid , context = context )
2012-08-24 13:21:25 +00:00
if not flag :
_logger . warning ( " %s " , gengo )
else :
2014-04-03 15:17:46 +00:00
offset = 0
2014-06-20 15:33:09 +00:00
all_translation_ids = translation_pool . search ( cr , uid , [ ( ' state ' , ' = ' , ' inprogress ' ) , ( ' gengo_translation ' , ' in ' , ( ' machine ' , ' standard ' , ' pro ' , ' ultra ' ) ) , ( ' order_id ' , " != " , False ) ] , context = context )
2014-04-03 15:17:46 +00:00
while True :
2014-04-07 17:46:21 +00:00
translation_ids = all_translation_ids [ offset : offset + limit ]
2014-04-09 21:45:09 +00:00
offset + = limit
if not translation_ids :
2014-04-03 15:17:46 +00:00
break
2014-06-20 15:33:09 +00:00
terms_progress = {
' gengo_order_ids ' : set ( ) ,
' ir_translation_ids ' : set ( ) ,
}
2014-04-09 21:45:09 +00:00
translation_terms = translation_pool . browse ( cr , uid , translation_ids , context = context )
2014-06-20 15:33:09 +00:00
for term in translation_terms :
terms_progress [ ' gengo_order_ids ' ] . add ( term . order_id )
terms_progress [ ' ir_translation_ids ' ] . add ( tools . ustr ( term . id ) )
for order_id in terms_progress [ ' gengo_order_ids ' ] :
order_response = gengo . getTranslationOrderJobs ( id = order_id )
jobs_approved = order_response . get ( ' response ' , [ ] ) . get ( ' order ' , [ ] ) . get ( ' jobs_approved ' , [ ] )
gengo_ids = ' , ' . join ( jobs_approved )
if gengo_ids : # Need to check, because getTranslationJobBatch don't catch this case and so call the getTranslationJobs because no ids in url
2014-04-09 21:45:09 +00:00
try :
job_response = gengo . getTranslationJobBatch ( id = gengo_ids )
except :
continue
if job_response [ ' opstat ' ] == ' ok ' :
for job in job_response [ ' response ' ] . get ( ' jobs ' , [ ] ) :
2014-06-20 15:33:09 +00:00
if job . get ( ' custom_data ' ) in terms_progress [ ' ir_translation_ids ' ] :
self . _update_terms_job ( cr , uid , job , context = context )
2012-08-30 16:14:29 +00:00
return True
2014-04-09 21:45:09 +00:00
def _update_terms_job ( self , cr , uid , job , context = None ) :
translation_pool = self . pool . get ( ' ir.translation ' )
tid = int ( job [ ' custom_data ' ] )
vals = { }
2014-06-20 15:33:09 +00:00
if job . get ( ' status ' , False ) in ( ' queued ' , ' available ' , ' pending ' , ' reviewable ' ) :
2014-04-09 21:45:09 +00:00
vals [ ' state ' ] = ' inprogress '
2014-06-20 15:33:09 +00:00
if job . get ( ' body_tgt ' , False ) and job . get ( ' status ' , False ) == ' approved ' :
2014-04-09 21:45:09 +00:00
vals [ ' value ' ] = job [ ' body_tgt ' ]
if job . get ( ' status ' , False ) in ( ' approved ' , ' canceled ' ) :
vals [ ' state ' ] = ' translated '
if vals :
translation_pool . write ( cr , uid , [ tid ] , vals , context = context )
2014-06-20 15:33:09 +00:00
def _update_terms ( self , cr , uid , response , term_ids , context = None ) :
2012-08-30 16:14:29 +00:00
"""
Update the terms after their translation were requested to Gengo
"""
2014-06-20 15:33:09 +00:00
translation_pool = self . pool . get ( ' ir.translation ' )
vals = {
' order_id ' : response . get ( ' order_id ' , ' ' ) ,
' state ' : ' inprogress '
}
translation_pool . write ( cr , uid , term_ids , vals , context = context )
jobs = response . get ( ' jobs ' , [ ] )
if jobs :
2012-08-30 16:14:29 +00:00
for t_id , res in jobs . items ( ) :
2014-04-09 21:45:09 +00:00
self . _update_terms_job ( cr , uid , res , context = context )
2014-06-20 15:33:09 +00:00
2012-08-30 16:14:29 +00:00
return
def pack_jobs_request ( self , cr , uid , term_ids , context = None ) :
''' prepare the terms that will be requested to gengo and returns them in a dictionary with following format
{ ' jobs ' : {
' term1.id ' : { . . . }
' term2.id ' : { . . . }
}
} '''
2014-06-23 09:08:53 +00:00
base_url = self . pool . get ( ' ir.config_parameter ' ) . get_param ( cr , uid , ' web.base.url ' )
2012-08-30 16:14:29 +00:00
translation_pool = self . pool . get ( ' ir.translation ' )
jobs = { }
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
auto_approve = 1 if user . company_id . gengo_auto_approve else 0
for term in translation_pool . browse ( cr , uid , term_ids , context = context ) :
if re . search ( r " \ w " , term . src or " " ) :
2014-04-09 21:45:09 +00:00
comment = user . company_id . gengo_comment or ' '
if term . gengo_comment :
2014-06-20 15:33:09 +00:00
comment + = ' \n ' + term . gengo_comment
2014-04-09 21:45:09 +00:00
jobs [ time . strftime ( ' % Y % m %d % H % M % S ' ) + ' - ' + str ( term . id ) ] = {
' type ' : ' text ' ,
' slug ' : ' Single :: English to ' + term . lang ,
' tier ' : tools . ustr ( term . gengo_translation ) ,
' custom_data ' : str ( term . id ) ,
' body_src ' : term . src ,
' lc_src ' : ' en ' ,
' lc_tgt ' : translation_pool . _get_gengo_corresponding_language ( term . lang ) ,
' auto_approve ' : auto_approve ,
' comment ' : comment ,
2014-06-23 09:08:53 +00:00
' callback_url ' : " %s /website/gengo_callback?pgk= %s &db= %s " % ( base_url , self . get_gengo_key ( cr ) , cr . dbname )
2012-08-30 16:14:29 +00:00
}
2014-06-20 15:33:09 +00:00
return { ' jobs ' : jobs , ' as_group ' : 0 }
2012-08-30 16:14:29 +00:00
2014-04-03 15:17:46 +00:00
def _send_translation_terms ( self , cr , uid , term_ids , context = None ) :
2012-08-30 16:14:29 +00:00
"""
Send a request to Gengo with all the term_ids in a different job , get the response and update the terms in
database accordingly .
"""
flag , gengo = self . gengo_authentication ( cr , uid , context = context )
if flag :
request = self . pack_jobs_request ( cr , uid , term_ids , context = context )
if request [ ' jobs ' ] :
result = gengo . postTranslationJobs ( jobs = request )
if result [ ' opstat ' ] == ' ok ' :
2014-06-20 15:33:09 +00:00
self . _update_terms ( cr , uid , result [ ' response ' ] , term_ids , context = context )
2012-08-30 16:14:29 +00:00
else :
_logger . error ( gengo )
2012-08-23 13:42:57 +00:00
return True
2012-08-06 10:25:17 +00:00
2012-08-29 08:26:47 +00:00
def _sync_request ( self , cr , uid , limit = GENGO_DEFAULT_LIMIT , context = None ) :
2012-08-30 16:14:29 +00:00
"""
This scheduler will send a job request to the gengo , which terms are
2014-05-27 13:51:09 +00:00
waiing to be translated and for which gengo_translation is enabled .
2012-08-30 16:14:29 +00:00
2014-05-27 13:51:09 +00:00
A special key ' gengo_language ' can be passed in the context in order to
request only translations of that language only . Its value is the language
2014-07-09 11:39:38 +00:00
ID in Odoo .
2012-08-30 16:14:29 +00:00
"""
2012-08-06 07:40:35 +00:00
if context is None :
2012-08-06 10:25:17 +00:00
context = { }
2012-08-24 13:21:25 +00:00
language_pool = self . pool . get ( ' res.lang ' )
translation_pool = self . pool . get ( ' ir.translation ' )
2014-06-20 15:33:09 +00:00
domain = [ ( ' state ' , ' = ' , ' to_translate ' ) , ( ' gengo_translation ' , ' in ' , ( ' machine ' , ' standard ' , ' pro ' , ' ultra ' ) ) , ( ' order_id ' , " = " , False ) ]
2014-04-09 21:45:09 +00:00
if context . get ( ' gengo_language ' , False ) :
lc = language_pool . browse ( cr , uid , context [ ' gengo_language ' ] , context = context ) . code
2014-06-20 15:33:09 +00:00
domain . append ( ( ' lang ' , ' = ' , lc ) )
2014-04-09 21:45:09 +00:00
all_term_ids = translation_pool . search ( cr , uid , domain , context = context )
2012-08-06 07:40:35 +00:00
try :
2014-04-03 15:17:46 +00:00
offset = 0
while True :
#search for the n first terms to translate
2014-04-07 17:46:21 +00:00
term_ids = all_term_ids [ offset : offset + limit ]
2014-04-03 15:17:46 +00:00
if term_ids :
offset + = limit
2014-04-07 17:46:21 +00:00
self . _send_translation_terms ( cr , uid , term_ids , context = context )
2014-04-03 15:17:46 +00:00
_logger . info ( " %s Translation terms have been posted to Gengo successfully " , len ( term_ids ) )
2014-04-07 17:46:21 +00:00
if not len ( term_ids ) == limit :
2014-04-03 15:17:46 +00:00
break
2012-08-06 07:40:35 +00:00
except Exception , e :
2012-08-24 13:21:25 +00:00
_logger . error ( " %s " , e )
2012-08-06 07:40:35 +00:00
2012-08-06 10:25:17 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: