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 print "\x1b[31;1mDEBUG\x1b[m:", message
24 class XmppTranslator(Thread
):
26 def __init__(self
, jid
, password
):
31 self
._input_queue
= Queue(0)
32 self
._output_queue
= Queue(0)
33 self
._last_text_to_translate
= {}
35 self
._jid
= xmpp
.JID(jid
)
36 self
._password
= password
37 if self
._jid
.getResource() == '':
38 self
._jid
.setResource('translator')
40 self
._client
= xmpp
.Client(self
._jid
.getDomain(), debug
=[])
43 if self
._client
and not self
._client
.isConnected():
45 self
._client
.sendPresence(typ
='unavailable')
46 self
._client
.disconnect()
50 if not self
._client
.connect():
53 raise IOError, "can't connect to '%s'" % self
._jid
.getDomain()
54 self
._client
.RegisterHandler('message', self
._messageHandler
)
56 auth
= self
._client
.auth(self
._jid
.getNode(), self
._password
,
57 self
._jid
.getResource())
59 raise IOError, "unable to authenticate '%s'" % self
._jid
.getNode()
60 self
._client
.sendInitPresence(requestRoster
=0)
62 def _messageHandler(self
, client
, message
):
63 if message
.getType() == 'error':
65 translation_path
= message
.getFrom().getNode()
66 text
= message
.getBody()
67 self
._output_queue
.put( (translation_path
, text
) )
68 raise xmpp
.NodeProcessed
70 def _process_input_queue(self
):
71 if self
._input_queue
.empty():
73 # process pending translation job
74 translation_path
, text
= self
._input_queue
.get()
75 jid
= '%s@bot.talk.google.com' % translation_path
76 message
= xmpp
.Message(to
=jid
, typ
='chat', body
=text
)
77 self
._client
.send(message
)
78 DEBUG("sent [%s] to '%s'." % (text
, jid
))
79 self
._input_queue
.task_done()
83 self
._client
.Process(1)
85 self
._process_input_queue()
86 self
._client
.Process(1)
88 def request_translation(self
, translation_path
, text
):
89 text
= text
.strip().replace('\r\n','\n')
90 # skip consecutive identical requests
91 if text
== self
._last_text_to_translate
.get(translation_path
):
93 self
._last_text_to_translate
[translation_path
] = text
94 # remove any pending translation job
95 while not self
._input_queue
.empty():
96 self
._input_queue
.get()
97 DEBUG("removed a pending translation job")
98 self
._input_queue
.task_done()
99 # put a new translation job
100 self
._input_queue
.put( (translation_path
, text
) )
102 def translation_result(self
):
103 if self
._output_queue
.empty():
105 translation_path
, text
= self
._output_queue
.get()
106 return translation_path
, text
108 def translation_done(self
):
109 self
._output_queue
.task_done()
111 class GtkTranslator(object):
113 def __init__(self
, translator
):
114 self
._translator
= translator
118 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
119 self
.window
.set_title(u
"PygTranslator")
120 self
.window
.set_border_width(0)
121 self
.window
.connect("destroy", lambda w
: gtk
.main_quit())
122 self
.window
.connect("delete_event", self
._delete_event
)
124 vbox
= gtk
.VBox(True, 0)
127 textview
= gtk
.TextView()
128 textview
.set_size_request(400, 100)
129 textview
.set_wrap_mode(gtk
.WRAP_WORD
)
131 scroll
= gtk
.ScrolledWindow()
134 frame
= gtk
.Frame(u
"Texte en français")
135 frame
.connect("key_release_event", self
._text_change
, 'fr')
136 frame
.connect("button_release_event", self
._text_change
, 'fr')
139 vbox
.pack_start(frame
, True, True, 0)
140 self
._textbuf
['fr'] = textview
.get_buffer()
142 textview
= gtk
.TextView()
143 textview
.set_size_request(400, 100)
144 textview
.set_wrap_mode(gtk
.WRAP_WORD
)
146 scroll
= gtk
.ScrolledWindow()
149 frame
= gtk
.Frame(u
"Text in English")
150 frame
.connect("key_release_event", self
._text_change
, 'en')
151 frame
.connect("button_release_event", self
._text_change
, 'en')
154 vbox
.pack_start(frame
, True, True, 0)
155 self
._textbuf
['en'] = textview
.get_buffer()
157 self
.window
.add(vbox
)
160 def _delete_event(self
, widget
, event
, data
=None):
161 DEBUG("caught delete event")
165 def _text_change(self
, widget
, event
, lang
):
166 start
, end
= self
._textbuf
[lang
].get_bounds()
167 text
= self
._textbuf
[lang
].get_text(start
, end
)
168 other_lang
= (set(self
._textbuf
.keys()) - set((lang
,))).pop()
169 translation_path
= lang
+ '2' + other_lang
170 self
._translator
.request_translation(translation_path
, text
)
172 def _process_translation_result(self
):
174 # FIXME: to transform into an iterator...
176 r
= self
._translator
.translation_result()
179 translation_path
, text
= r
180 lang
= translation_path
[3:]
181 if lang
in self
._textbuf
:
184 DEBUG("unknown destination language '%s'" % lang
)
185 self
._translator
.translation_done()
186 for lang
, text
in result
.items():
187 self
._textbuf
[lang
].set_text(text
)
188 gobject
.timeout_add(300, self
._process_translation_result
)
191 DEBUG("running graphic interface")
192 gobject
.timeout_add(300, self
._process_translation_result
)
193 gtk
.gdk
.threads_init()
196 if __name__
== "__main__":
198 if len(sys
.argv
) != 3:
199 print "Usage: %s <jid> <password>" % sys
.argv
[0]
202 translator
= XmppTranslator(sys
.argv
[1], sys
.argv
[2])
205 pygtranslator
= GtkTranslator(translator
)
208 except KeyboardInterrupt:
211 translator
._quit
= True