1 #!/usr/bin/env python2.5
2 # -*- coding: utf-8 -*-
4 PygTranslator - pas de doc cette fois-ci... :-P
6 Copyright : Agence universitaire de la Francophonie
7 Licence : GNU General Public Licence, version 2
8 Auteur : Jean Christophe André
9 Date de création : 28 septembre 2009
12 from threading
import Thread
13 from Queue
import Queue
21 modules
= ['xmpp','gtk2','gobject']
22 print u
"Ce programme requiert l'installation des paquets Debian suivants :"
23 print u
"* python-" + "\n* python-".join(modules
)
29 print "\x1b[31;1mDEBUG\x1b[m:", message
32 class XmppTranslator(Thread
):
34 def __init__(self
, jid
, password
):
39 self
._input_queue
= Queue(0)
40 self
._output_queue
= Queue(0)
41 self
._last_text_to_translate
= {}
43 self
._jid
= xmpp
.JID(jid
)
44 self
._password
= password
45 if self
._jid
.getResource() == '':
46 self
._jid
.setResource('translator')
48 self
._client
= xmpp
.Client(self
._jid
.getDomain(), debug
=[])
51 if self
._client
and not self
._client
.isConnected():
53 self
._client
.sendPresence(typ
='unavailable')
54 self
._client
.disconnect()
58 if not self
._client
.connect():
61 raise IOError, "can't connect to '%s'" % self
._jid
.getDomain()
62 self
._client
.RegisterHandler('message', self
._messageHandler
)
64 auth
= self
._client
.auth(self
._jid
.getNode(), self
._password
,
65 self
._jid
.getResource())
67 raise IOError, "unable to authenticate '%s'" % self
._jid
.getNode()
68 self
._client
.sendInitPresence(requestRoster
=0)
70 def _messageHandler(self
, client
, message
):
71 if message
.getType() == 'error':
73 translation_path
= message
.getFrom().getNode()
74 text
= message
.getBody()
75 self
._output_queue
.put( (translation_path
, text
) )
76 raise xmpp
.NodeProcessed
78 def _process_input_queue(self
):
79 if self
._input_queue
.empty():
81 # process pending translation job
82 translation_path
, text
= self
._input_queue
.get()
83 jid
= '%s@bot.talk.google.com' % translation_path
84 message
= xmpp
.Message(to
=jid
, typ
='chat', body
=text
)
85 self
._client
.send(message
)
86 DEBUG("sent [%s] to '%s'." % (text
, jid
))
87 self
._input_queue
.task_done()
91 self
._client
.Process(1)
93 self
._process_input_queue()
94 self
._client
.Process(1)
96 def request_translation(self
, translation_path
, text
):
97 text
= text
.strip().replace('\r\n','\n')
98 # skip consecutive identical requests
99 if text
== self
._last_text_to_translate
.get(translation_path
):
101 self
._last_text_to_translate
[translation_path
] = text
102 # remove any pending translation job
103 while not self
._input_queue
.empty():
104 self
._input_queue
.get()
105 DEBUG("removed a pending translation job")
106 self
._input_queue
.task_done()
107 # put a new translation job
108 self
._input_queue
.put( (translation_path
, text
) )
110 def translation_result(self
):
111 if self
._output_queue
.empty():
113 translation_path
, text
= self
._output_queue
.get()
114 return translation_path
, text
116 def translation_done(self
):
117 self
._output_queue
.task_done()
119 class GtkTranslator(object):
121 def __init__(self
, translator
):
122 self
._translator
= translator
126 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
127 self
.window
.set_title(u
"PygTranslator")
128 self
.window
.set_border_width(0)
129 self
.window
.connect("destroy", lambda w
: gtk
.main_quit())
130 self
.window
.connect("delete_event", self
._delete_event
)
132 vbox
= gtk
.VBox(True, 0)
135 textview
= gtk
.TextView()
136 textview
.set_size_request(400, 100)
137 textview
.set_wrap_mode(gtk
.WRAP_WORD
)
139 scroll
= gtk
.ScrolledWindow()
142 frame
= gtk
.Frame(u
"Texte en français")
143 frame
.connect("key_release_event", self
._text_change
, 'fr')
144 frame
.connect("button_release_event", self
._text_change
, 'fr')
147 vbox
.pack_start(frame
, True, True, 0)
148 self
._textbuf
['fr'] = textview
.get_buffer()
150 textview
= gtk
.TextView()
151 textview
.set_size_request(400, 100)
152 textview
.set_wrap_mode(gtk
.WRAP_WORD
)
154 scroll
= gtk
.ScrolledWindow()
157 frame
= gtk
.Frame(u
"Text in English")
158 frame
.connect("key_release_event", self
._text_change
, 'en')
159 frame
.connect("button_release_event", self
._text_change
, 'en')
162 vbox
.pack_start(frame
, True, True, 0)
163 self
._textbuf
['en'] = textview
.get_buffer()
165 self
.window
.add(vbox
)
168 def _delete_event(self
, widget
, event
, data
=None):
169 DEBUG("caught delete event")
173 def _text_change(self
, widget
, event
, lang
):
174 start
, end
= self
._textbuf
[lang
].get_bounds()
175 text
= self
._textbuf
[lang
].get_text(start
, end
)
176 other_lang
= (set(self
._textbuf
.keys()) - set((lang
,))).pop()
177 translation_path
= lang
+ '2' + other_lang
178 self
._translator
.request_translation(translation_path
, text
)
180 def _process_translation_result(self
):
182 # FIXME: to transform into an iterator...
184 r
= self
._translator
.translation_result()
187 translation_path
, text
= r
188 lang
= translation_path
[3:]
189 if lang
in self
._textbuf
:
192 DEBUG("unknown destination language '%s'" % lang
)
193 self
._translator
.translation_done()
194 for lang
, text
in result
.items():
195 self
._textbuf
[lang
].set_text(text
)
196 gobject
.timeout_add(300, self
._process_translation_result
)
199 DEBUG("running graphic interface")
200 gobject
.timeout_add(300, self
._process_translation_result
)
201 gtk
.gdk
.threads_init()
204 if __name__
== "__main__":
205 if len(sys
.argv
) > 1 and sys
.argv
[1] == '-d':
208 if len(sys
.argv
) != 3:
209 print "Usage: %s [-d] <jid> <password>" % sys
.argv
[0]
212 translator
= XmppTranslator(sys
.argv
[1], sys
.argv
[2])
215 pygtranslator
= GtkTranslator(translator
)
218 except KeyboardInterrupt:
221 translator
._quit
= True