pygtranslator : mise à jour pour Precise
[progfou.git] / pygtranslator / pygtranslator.py
CommitLineData
4c412ef3 1#!/usr/bin/env python
e603e417
P
2# -*- coding: utf-8 -*-
3"""
4PygTranslator - pas de doc cette fois-ci... :-P
5
6Copyright : Agence universitaire de la Francophonie
7Licence : GNU General Public Licence, version 2
8Auteur : Jean Christophe André
9Date de création : 28 septembre 2009
10"""
f682a3c3 11import sys
e603e417
P
12from threading import Thread
13from Queue import Queue
f682a3c3
P
14try:
15 import xmpp
16 import pygtk
17 pygtk.require('2.0')
18 import gtk
19 import gobject
20except ImportError:
4c412ef3 21 modules = ['python-xmpp','python-gtk2','python-gobject']
f682a3c3 22 print u"Ce programme requiert l'installation des paquets Debian suivants :"
4c412ef3
P
23 print u" " + u" ".join(modules)
24 print u"Essayez ceci : sudo apt-get install " + u" ".join(modules)
f682a3c3
P
25 sys.exit(-1)
26
27debug = False
e603e417 28def DEBUG(message):
f682a3c3
P
29 if debug:
30 print "\x1b[31;1mDEBUG\x1b[m:", message
e603e417
P
31 return
32
33class XmppTranslator(Thread):
34
35 def __init__(self, jid, password):
36 Thread.__init__(self)
37 self.setDaemon(True)
69eefce0
P
38 self._quit = False
39
e603e417
P
40 self._input_queue = Queue(0)
41 self._output_queue = Queue(0)
69eefce0 42 self._last_text_to_translate = {}
e603e417
P
43
44 self._jid = xmpp.JID(jid)
45 self._password = password
46 if self._jid.getResource() == '':
47 self._jid.setResource('translator')
48
49 self._client = xmpp.Client(self._jid.getDomain(), debug=[])
50
51 def __del__(self):
52 if self._client and not self._client.isConnected():
53 return
54 self._client.sendPresence(typ='unavailable')
55 self._client.disconnect()
56
57 def _connect(self):
58 try:
59 if not self._client.connect():
60 raise IOError
61 except IOError:
62 raise IOError, "can't connect to '%s'" % self._jid.getDomain()
63 self._client.RegisterHandler('message', self._messageHandler)
64
65 auth = self._client.auth(self._jid.getNode(), self._password,
66 self._jid.getResource())
67 if not auth:
68 raise IOError, "unable to authenticate '%s'" % self._jid.getNode()
69 self._client.sendInitPresence(requestRoster=0)
70
71 def _messageHandler(self, client, message):
72 if message.getType() == 'error':
73 return
74 translation_path = message.getFrom().getNode()
75 text = message.getBody()
76 self._output_queue.put( (translation_path, text) )
77 raise xmpp.NodeProcessed
78
79 def _process_input_queue(self):
80 if self._input_queue.empty():
81 return
82 # process pending translation job
83 translation_path, text = self._input_queue.get()
84 jid = '%s@bot.talk.google.com' % translation_path
85 message = xmpp.Message(to=jid, typ='chat', body=text)
86 self._client.send(message)
87 DEBUG("sent [%s] to '%s'." % (text, jid))
88 self._input_queue.task_done()
89
90 def run(self):
91 self._connect()
92 self._client.Process(1)
93 while not self._quit:
94 self._process_input_queue()
95 self._client.Process(1)
96
97 def request_translation(self, translation_path, text):
69eefce0
P
98 text = text.strip().replace('\r\n','\n')
99 # skip consecutive identical requests
100 if text == self._last_text_to_translate.get(translation_path):
101 return
102 self._last_text_to_translate[translation_path] = text
e603e417
P
103 # remove any pending translation job
104 while not self._input_queue.empty():
105 self._input_queue.get()
106 DEBUG("removed a pending translation job")
107 self._input_queue.task_done()
108 # put a new translation job
109 self._input_queue.put( (translation_path, text) )
110
111 def translation_result(self):
112 if self._output_queue.empty():
113 return None
114 translation_path, text = self._output_queue.get()
115 return translation_path, text
116
117 def translation_done(self):
118 self._output_queue.task_done()
119
120class GtkTranslator(object):
121
122 def __init__(self, translator):
123 self._translator = translator
124
125 self._textbuf = {}
126
127 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
128 self.window.set_title(u"PygTranslator")
129 self.window.set_border_width(0)
130 self.window.connect("destroy", lambda w: gtk.main_quit())
69eefce0 131 self.window.connect("delete_event", self._delete_event)
e603e417
P
132
133 vbox = gtk.VBox(True, 0)
134 vbox.show()
135
136 textview = gtk.TextView()
137 textview.set_size_request(400, 100)
138 textview.set_wrap_mode(gtk.WRAP_WORD)
139 textview.show()
140 scroll = gtk.ScrolledWindow()
141 scroll.add(textview)
142 scroll.show()
143 frame = gtk.Frame(u"Texte en français")
69eefce0
P
144 frame.connect("key_release_event", self._text_change, 'fr')
145 frame.connect("button_release_event", self._text_change, 'fr')
e603e417
P
146 frame.add(scroll)
147 frame.show()
148 vbox.pack_start(frame, True, True, 0)
149 self._textbuf['fr'] = textview.get_buffer()
150
151 textview = gtk.TextView()
152 textview.set_size_request(400, 100)
153 textview.set_wrap_mode(gtk.WRAP_WORD)
154 textview.show()
155 scroll = gtk.ScrolledWindow()
156 scroll.add(textview)
157 scroll.show()
158 frame = gtk.Frame(u"Text in English")
69eefce0
P
159 frame.connect("key_release_event", self._text_change, 'en')
160 frame.connect("button_release_event", self._text_change, 'en')
e603e417
P
161 frame.add(scroll)
162 frame.show()
163 vbox.pack_start(frame, True, True, 0)
164 self._textbuf['en'] = textview.get_buffer()
165
166 self.window.add(vbox)
167 self.window.show()
168
69eefce0 169 def _delete_event(self, widget, event, data=None):
e603e417
P
170 DEBUG("caught delete event")
171 gtk.main_quit()
172 return False
173
69eefce0 174 def _text_change(self, widget, event, lang):
e603e417
P
175 start, end = self._textbuf[lang].get_bounds()
176 text = self._textbuf[lang].get_text(start, end)
177 other_lang = (set(self._textbuf.keys()) - set((lang,))).pop()
178 translation_path = lang + '2' + other_lang
179 self._translator.request_translation(translation_path, text)
180
69eefce0 181 def _process_translation_result(self):
e603e417
P
182 result = {}
183 # FIXME: to transform into an iterator...
184 while True:
185 r = self._translator.translation_result()
186 if r is None:
187 break
188 translation_path, text = r
189 lang = translation_path[3:]
190 if lang in self._textbuf:
191 result[lang] = text
192 else:
193 DEBUG("unknown destination language '%s'" % lang)
194 self._translator.translation_done()
195 for lang, text in result.items():
196 self._textbuf[lang].set_text(text)
69eefce0
P
197 gobject.timeout_add(300, self._process_translation_result)
198
199 def run(self):
200 DEBUG("running graphic interface")
201 gobject.timeout_add(300, self._process_translation_result)
202 gtk.gdk.threads_init()
203 gtk.main()
e603e417
P
204
205if __name__ == "__main__":
f682a3c3
P
206 if len(sys.argv) > 1 and sys.argv[1] == '-d':
207 debug = True
208 del(sys.argv[1])
e603e417 209 if len(sys.argv) != 3:
f682a3c3 210 print "Usage: %s [-d] <jid> <password>" % sys.argv[0]
e603e417
P
211 sys.exit(1)
212
213 translator = XmppTranslator(sys.argv[1], sys.argv[2])
214 translator.start()
215
216 pygtranslator = GtkTranslator(translator)
217 try:
218 pygtranslator.run()
219 except KeyboardInterrupt:
220 pass
221
222 translator._quit = True
223 translator.join()
224
225 sys.exit(0)
226