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/>.
#
##############################################################################
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
from openerp import tools
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 :
from mygengo import MyGengo
except ImportError :
_logger . warning ( ' Gengo library not found, Gengo features disabled. If you plan to use it, please install the mygengo library from http://pypi.python.org/pypi/mygengo ' )
class MyGengo ( object ) :
def __init__ ( self , * args , * * kwargs ) :
# no context for translations - so don't bother
raise ImportError ( ' Gengo library not found, please install mygengo from http://pypi.python.org/pypi/mygengo ' )
2012-08-29 08:26:47 +00:00
GENGO_DEFAULT_LIMIT = 20
2012-08-30 16:14:29 +00:00
DEFAULT_CRON_VALS = {
2012-08-24 13:21:25 +00:00
' active ' : True ,
2012-08-28 11:04:26 +00:00
' interval_number ' : 20 ,
2012-08-24 13:21:25 +00:00
' interval_type ' : ' minutes ' ,
2012-08-30 16:14:29 +00:00
' model ' : " ' base.gengo.translations ' " ,
2012-08-29 10:10:03 +00:00
' args ' : " ' ( %s ,) ' " % ( str ( GENGO_DEFAULT_LIMIT ) ) ,
2012-08-23 13:42:57 +00:00
}
2012-08-06 10:25:17 +00:00
2012-08-30 16:14:29 +00:00
class base_gengo_translations ( osv . osv_memory ) :
2012-08-06 07:40:35 +00:00
2012-08-30 16:14:29 +00:00
_name = ' base.gengo.translations '
_columns = {
' restart_send_job ' : fields . boolean ( " Restart Sending Job " ) ,
2012-11-16 13:50:21 +00:00
' lang_id ' : fields . many2one ( ' res.lang ' , ' Language ' , required = True ) ,
2012-08-30 16:14:29 +00:00
}
2012-08-27 10:54:13 +00:00
2012-08-27 06:52:18 +00:00
def gengo_authentication ( self , cr , uid , context = None ) :
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
* as second element : the connection , if it was a success , or the error message returned by
Gengo when the connection failed .
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
translated .
'''
2012-08-29 08:26:47 +00:00
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , 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 :
gengo = MyGengo (
public_key = user . company_id . gengo_public_key . encode ( ' ascii ' ) ,
private_key = user . company_id . gengo_private_key . encode ( ' ascii ' ) ,
)
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-30 16:14:29 +00:00
def do_check_schedular ( self , cr , uid , xml_id , name , fn , context = None ) :
2012-08-23 13:42:57 +00:00
"""
2012-08-30 16:14:29 +00:00
This function is used to reset a cron to its default values , or to recreate it if it was deleted .
2012-08-23 13:42:57 +00:00
"""
cron_pool = self . pool . get ( ' ir.cron ' )
2012-08-30 16:14:29 +00:00
cron_vals = DEFAULT_CRON_VALS . copy ( )
cron_vals . update ( { ' name ' : name , " function " : fn } )
2012-08-06 07:40:35 +00:00
try :
2012-08-24 13:21:25 +00:00
res = [ ]
2012-11-16 13:50:21 +00:00
_ , res = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' base_gengo ' , xml_id )
2012-08-30 16:14:29 +00:00
cron_pool . write ( cr , uid , [ res ] , cron_vals , context = context )
2012-08-23 13:42:57 +00:00
except :
2012-08-29 09:50:22 +00:00
#the cron job was not found, probably deleted previously, so we create it again using default values
2012-08-30 16:14:29 +00:00
cron_vals . update ( { ' numbercall ' : - 1 } )
return cron_pool . create ( cr , uid , cron_vals , context = context )
2012-08-06 10:25:17 +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 .
'''
2012-08-23 13:42:57 +00:00
if context == None :
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
#send immediately a new request for the selected language (if any)
ctx = context . copy ( )
ctx [ ' gengo_language ' ] = wizard . lang_id . id
self . _sync_request ( cr , uid , limit = GENGO_DEFAULT_LIMIT , context = ctx )
2012-08-31 10:01:43 +00:00
self . _sync_response ( cr , uid , limit = GENGO_DEFAULT_LIMIT , context = ctx )
2012-08-30 16:14:29 +00:00
#check the cron jobs and eventually restart/recreate them
if wizard . restart_send_job :
self . do_check_schedular ( cr , uid , ' gengo_sync_send_request_scheduler ' , _ ( ' Gengo Sync Translation (Request) ' ) , ' _sync_request ' , context = context )
2012-08-31 09:18:51 +00:00
self . do_check_schedular ( cr , uid , ' gengo_sync_receive_request_scheduler ' , _ ( ' Gengo Sync Translation (Response) ' ) , ' _sync_response ' , context = context )
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
Gengo . It will read translated terms and comments from Gengo and will
update respective ir . translation in openerp .
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 :
2012-08-30 16:14:29 +00:00
translation_id = translation_pool . search ( cr , uid , [ ( ' state ' , ' = ' , ' inprogress ' ) , ( ' gengo_translation ' , ' in ' , ( ' machine ' , ' standard ' , ' pro ' , ' ultra ' ) ) ] , limit = limit , context = context )
for term in translation_pool . browse ( cr , uid , translation_id , context = context ) :
2012-08-28 11:37:55 +00:00
up_term = up_comment = 0
2012-08-27 10:54:13 +00:00
if term . job_id :
vals = { }
job_response = gengo . getTranslationJob ( id = term . job_id )
if job_response [ ' opstat ' ] != ' ok ' :
2012-08-29 08:26:47 +00:00
_logger . warning ( " Invalid Response! Skipping translation Terms with `id` %s . " % ( term . job_id ) )
2012-08-27 10:54:13 +00:00
continue
2012-08-24 13:21:25 +00:00
if job_response [ ' response ' ] [ ' job ' ] [ ' status ' ] == ' approved ' :
2012-08-27 10:54:13 +00:00
vals . update ( { ' state ' : ' translated ' ,
2012-08-29 10:10:03 +00:00
' value ' : job_response [ ' response ' ] [ ' job ' ] [ ' body_tgt ' ] } )
2012-08-28 11:37:55 +00:00
up_term + = 1
2012-08-27 10:54:13 +00:00
job_comment = gengo . getTranslationJobComments ( id = term . job_id )
if job_comment [ ' opstat ' ] == ' ok ' :
gengo_comments = " "
for comment in job_comment [ ' response ' ] [ ' thread ' ] :
2012-08-30 16:14:29 +00:00
gengo_comments + = _ ( ' %s \n \n -- \n Commented on %s by %s . ' ) % ( comment [ ' body ' ] , time . ctime ( comment [ ' ctime ' ] ) , comment [ ' author ' ] )
2012-08-29 08:26:47 +00:00
vals . update ( { ' gengo_comment ' : gengo_comments } )
2012-08-30 16:14:29 +00:00
up_comment + = 1
2012-08-27 10:54:13 +00:00
if vals :
2012-08-30 16:14:29 +00:00
translation_pool . write ( cr , uid , term . id , vals )
_logger . info ( " Successfully Updated ` %d ` terms and %d Comments. " % ( up_term , up_comment ) )
else :
_logger . warning ( " %s " , ' Cannot retrieve the Gengo job ID for translation %s : %s ' % ( term . id , term . src ) )
return True
def _update_terms ( self , cr , uid , response , context = None ) :
"""
Update the terms after their translation were requested to Gengo
"""
translation_pool = self . pool . get ( ' ir.translation ' )
for jobs in response [ ' jobs ' ] :
for t_id , res in jobs . items ( ) :
vals = { }
t_id = int ( t_id )
tier = translation_pool . read ( cr , uid , [ t_id ] , [ ' gengo_translation ' ] , context = context ) [ 0 ] [ ' gengo_translation ' ]
if tier == " machine " :
vals . update ( { ' value ' : res [ ' body_tgt ' ] , ' state ' : ' translated ' } )
else :
vals . update ( { ' job_id ' : res [ ' job_id ' ] , ' state ' : ' inprogress ' } )
translation_pool . write ( cr , uid , [ t_id ] , vals , context = context )
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 ' : { . . . }
}
} '''
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 " " ) :
jobs [ term . id ] = { ' type ' : ' text ' ,
' slug ' : ' single::English to ' + term . lang ,
' tier ' : tools . ustr ( term . gengo_translation ) ,
' body_src ' : term . src ,
' lc_src ' : ' en ' ,
' lc_tgt ' : translation_pool . _get_gengo_corresponding_language ( term . lang ) ,
' auto_approve ' : auto_approve ,
' comment ' : user . company_id . gengo_comment ,
}
return { ' jobs ' : jobs }
def _send_translation_terms ( self , cr , uid , term_ids , context = None ) :
"""
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 ' :
self . _update_terms ( cr , uid , result [ ' response ' ] , context = context )
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
waiing to be translated and for which gengo_translation is enabled .
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
ID in openerp .
"""
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 ' )
2012-08-06 07:40:35 +00:00
try :
2012-08-30 16:14:29 +00:00
#by default, the request will be made for all terms that needs it, whatever the language
lang_ids = language_pool . search ( cr , uid , [ ] , context = context )
if context . get ( ' gengo_language ' ) :
#but if this specific key is given, then we restrict the request on terms of this language only
lang_ids = [ context . get ( ' gengo_language ' ) ]
2012-08-29 08:26:47 +00:00
langs = [ lang . code for lang in language_pool . browse ( cr , uid , lang_ids , context = context ) ]
2012-08-30 16:14:29 +00:00
#search for the n first terms to translate
term_ids = translation_pool . search ( cr , uid , [ ( ' state ' , ' = ' , ' to_translate ' ) , ( ' gengo_translation ' , ' in ' , ( ' machine ' , ' standard ' , ' pro ' , ' ultra ' ) ) , ( ' lang ' , ' in ' , langs ) ] , limit = limit , context = context )
2012-08-24 13:21:25 +00:00
if term_ids :
2012-08-30 16:14:29 +00:00
self . _send_translation_terms ( cr , uid , term_ids , context = context )
_logger . info ( " %s Translation terms have been posted to Gengo successfully " , len ( term_ids ) )
2012-08-23 13:42:57 +00:00
else :
2012-08-24 13:21:25 +00:00
_logger . info ( ' No Translation terms to process. ' )
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: