--- /dev/null
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+"""
+PygTranslator - pas de doc cette fois-ci... :-P
+
+Copyright : Agence universitaire de la Francophonie
+Licence : GNU General Public Licence, version 2
+Auteur : Jean Christophe André
+Date de création : 28 septembre 2009
+"""
+
+from threading import Thread
+from Queue import Queue
+import xmpp
+
+import pygtk
+pygtk.require('2.0')
+import gtk, gobject
+
+def DEBUG(message):
+ #print "\x1b[31;1mDEBUG\x1b[m:", message
+ return
+
+class XmppTranslator(Thread):
+
+ def __init__(self, jid, password):
+ Thread.__init__(self)
+ self.setDaemon(True)
+ self._input_queue = Queue(0)
+ self._output_queue = Queue(0)
+ self._quit = False
+
+ self._jid = xmpp.JID(jid)
+ self._password = password
+ if self._jid.getResource() == '':
+ self._jid.setResource('translator')
+
+ self._client = xmpp.Client(self._jid.getDomain(), debug=[])
+
+ def __del__(self):
+ if self._client and not self._client.isConnected():
+ return
+ self._client.sendPresence(typ='unavailable')
+ self._client.disconnect()
+
+ def _connect(self):
+ try:
+ if not self._client.connect():
+ raise IOError
+ except IOError:
+ raise IOError, "can't connect to '%s'" % self._jid.getDomain()
+ self._client.RegisterHandler('message', self._messageHandler)
+
+ auth = self._client.auth(self._jid.getNode(), self._password,
+ self._jid.getResource())
+ if not auth:
+ raise IOError, "unable to authenticate '%s'" % self._jid.getNode()
+ self._client.sendInitPresence(requestRoster=0)
+
+ def _messageHandler(self, client, message):
+ if message.getType() == 'error':
+ return
+ translation_path = message.getFrom().getNode()
+ text = message.getBody()
+ self._output_queue.put( (translation_path, text) )
+ raise xmpp.NodeProcessed
+
+ def _process_input_queue(self):
+ if self._input_queue.empty():
+ return
+ # process pending translation job
+ translation_path, text = self._input_queue.get()
+ jid = '%s@bot.talk.google.com' % translation_path
+ message = xmpp.Message(to=jid, typ='chat', body=text)
+ self._client.send(message)
+ DEBUG("sent [%s] to '%s'." % (text, jid))
+ self._input_queue.task_done()
+
+ def run(self):
+ self._connect()
+ self._client.Process(1)
+ while not self._quit:
+ self._process_input_queue()
+ self._client.Process(1)
+
+ def request_translation(self, translation_path, text):
+ # remove any pending translation job
+ while not self._input_queue.empty():
+ self._input_queue.get()
+ DEBUG("removed a pending translation job")
+ self._input_queue.task_done()
+ # put a new translation job
+ self._input_queue.put( (translation_path, text) )
+
+ def translation_result(self):
+ if self._output_queue.empty():
+ return None
+ translation_path, text = self._output_queue.get()
+ return translation_path, text
+
+ def translation_done(self):
+ self._output_queue.task_done()
+
+class GtkTranslator(object):
+
+ def __init__(self, translator):
+ self._translator = translator
+
+ self._textbuf = {}
+
+ self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ self.window.set_title(u"PygTranslator")
+ self.window.set_border_width(0)
+ self.window.connect("destroy", lambda w: gtk.main_quit())
+ self.window.connect("delete_event", self.delete_event)
+
+ vbox = gtk.VBox(True, 0)
+ vbox.show()
+
+ textview = gtk.TextView()
+ textview.set_size_request(400, 100)
+ textview.set_wrap_mode(gtk.WRAP_WORD)
+ textview.show()
+ scroll = gtk.ScrolledWindow()
+ scroll.add(textview)
+ scroll.show()
+ frame = gtk.Frame(u"Texte en français")
+ frame.connect("key_release_event", self.key_release_event, 'fr')
+ frame.add(scroll)
+ frame.show()
+ vbox.pack_start(frame, True, True, 0)
+ self._textbuf['fr'] = textview.get_buffer()
+
+ textview = gtk.TextView()
+ textview.set_size_request(400, 100)
+ textview.set_wrap_mode(gtk.WRAP_WORD)
+ textview.show()
+ scroll = gtk.ScrolledWindow()
+ scroll.add(textview)
+ scroll.show()
+ frame = gtk.Frame(u"Text in English")
+ frame.connect("key_release_event", self.key_release_event, 'en')
+ frame.add(scroll)
+ frame.show()
+ vbox.pack_start(frame, True, True, 0)
+ self._textbuf['en'] = textview.get_buffer()
+
+ self.window.add(vbox)
+ self.window.show()
+
+ def run(self):
+ DEBUG("running graphic interface")
+ gobject.timeout_add(100, self.process_translation_result)
+ gtk.gdk.threads_init()
+ gtk.main()
+
+ def delete_event(self, widget, event, data=None):
+ DEBUG("caught delete event")
+ gtk.main_quit()
+ return False
+
+ def key_release_event(self, widget, event, lang):
+ start, end = self._textbuf[lang].get_bounds()
+ text = self._textbuf[lang].get_text(start, end)
+ other_lang = (set(self._textbuf.keys()) - set((lang,))).pop()
+ translation_path = lang + '2' + other_lang
+ self._translator.request_translation(translation_path, text)
+
+ def process_translation_result(self):
+ result = {}
+ # FIXME: to transform into an iterator...
+ while True:
+ r = self._translator.translation_result()
+ if r is None:
+ break
+ translation_path, text = r
+ lang = translation_path[3:]
+ if lang in self._textbuf:
+ result[lang] = text
+ else:
+ DEBUG("unknown destination language '%s'" % lang)
+ self._translator.translation_done()
+ for lang, text in result.items():
+ self._textbuf[lang].set_text(text)
+ gobject.timeout_add(100, self.process_translation_result)
+
+if __name__ == "__main__":
+ import sys
+ if len(sys.argv) != 3:
+ print "Usage: %s <jid> <password>" % sys.argv[0]
+ sys.exit(1)
+
+ translator = XmppTranslator(sys.argv[1], sys.argv[2])
+ translator.start()
+
+ pygtranslator = GtkTranslator(translator)
+ try:
+ pygtranslator.run()
+ except KeyboardInterrupt:
+ pass
+
+ translator._quit = True
+ translator.join()
+
+ sys.exit(0)
+