Quelques optimisations pour réduire les requêtes chez Google.
[progfou.git] / pygtranslator / pygtranslator.py
... / ...
CommitLineData
1#!/usr/bin/env python2.5
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"""
11
12from threading import Thread
13from Queue import Queue
14import xmpp
15
16import pygtk
17pygtk.require('2.0')
18import gtk, gobject
19
20def DEBUG(message):
21 print "\x1b[31;1mDEBUG\x1b[m:", message
22 return
23
24class XmppTranslator(Thread):
25
26 def __init__(self, jid, password):
27 Thread.__init__(self)
28 self.setDaemon(True)
29 self._quit = False
30
31 self._input_queue = Queue(0)
32 self._output_queue = Queue(0)
33 self._last_text_to_translate = {}
34
35 self._jid = xmpp.JID(jid)
36 self._password = password
37 if self._jid.getResource() == '':
38 self._jid.setResource('translator')
39
40 self._client = xmpp.Client(self._jid.getDomain(), debug=[])
41
42 def __del__(self):
43 if self._client and not self._client.isConnected():
44 return
45 self._client.sendPresence(typ='unavailable')
46 self._client.disconnect()
47
48 def _connect(self):
49 try:
50 if not self._client.connect():
51 raise IOError
52 except IOError:
53 raise IOError, "can't connect to '%s'" % self._jid.getDomain()
54 self._client.RegisterHandler('message', self._messageHandler)
55
56 auth = self._client.auth(self._jid.getNode(), self._password,
57 self._jid.getResource())
58 if not auth:
59 raise IOError, "unable to authenticate '%s'" % self._jid.getNode()
60 self._client.sendInitPresence(requestRoster=0)
61
62 def _messageHandler(self, client, message):
63 if message.getType() == 'error':
64 return
65 translation_path = message.getFrom().getNode()
66 text = message.getBody()
67 self._output_queue.put( (translation_path, text) )
68 raise xmpp.NodeProcessed
69
70 def _process_input_queue(self):
71 if self._input_queue.empty():
72 return
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()
80
81 def run(self):
82 self._connect()
83 self._client.Process(1)
84 while not self._quit:
85 self._process_input_queue()
86 self._client.Process(1)
87
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):
92 return
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) )
101
102 def translation_result(self):
103 if self._output_queue.empty():
104 return None
105 translation_path, text = self._output_queue.get()
106 return translation_path, text
107
108 def translation_done(self):
109 self._output_queue.task_done()
110
111class GtkTranslator(object):
112
113 def __init__(self, translator):
114 self._translator = translator
115
116 self._textbuf = {}
117
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)
123
124 vbox = gtk.VBox(True, 0)
125 vbox.show()
126
127 textview = gtk.TextView()
128 textview.set_size_request(400, 100)
129 textview.set_wrap_mode(gtk.WRAP_WORD)
130 textview.show()
131 scroll = gtk.ScrolledWindow()
132 scroll.add(textview)
133 scroll.show()
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')
137 frame.add(scroll)
138 frame.show()
139 vbox.pack_start(frame, True, True, 0)
140 self._textbuf['fr'] = textview.get_buffer()
141
142 textview = gtk.TextView()
143 textview.set_size_request(400, 100)
144 textview.set_wrap_mode(gtk.WRAP_WORD)
145 textview.show()
146 scroll = gtk.ScrolledWindow()
147 scroll.add(textview)
148 scroll.show()
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')
152 frame.add(scroll)
153 frame.show()
154 vbox.pack_start(frame, True, True, 0)
155 self._textbuf['en'] = textview.get_buffer()
156
157 self.window.add(vbox)
158 self.window.show()
159
160 def _delete_event(self, widget, event, data=None):
161 DEBUG("caught delete event")
162 gtk.main_quit()
163 return False
164
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)
171
172 def _process_translation_result(self):
173 result = {}
174 # FIXME: to transform into an iterator...
175 while True:
176 r = self._translator.translation_result()
177 if r is None:
178 break
179 translation_path, text = r
180 lang = translation_path[3:]
181 if lang in self._textbuf:
182 result[lang] = text
183 else:
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)
189
190 def run(self):
191 DEBUG("running graphic interface")
192 gobject.timeout_add(300, self._process_translation_result)
193 gtk.gdk.threads_init()
194 gtk.main()
195
196if __name__ == "__main__":
197 import sys
198 if len(sys.argv) != 3:
199 print "Usage: %s <jid> <password>" % sys.argv[0]
200 sys.exit(1)
201
202 translator = XmppTranslator(sys.argv[1], sys.argv[2])
203 translator.start()
204
205 pygtranslator = GtkTranslator(translator)
206 try:
207 pygtranslator.run()
208 except KeyboardInterrupt:
209 pass
210
211 translator._quit = True
212 translator.join()
213
214 sys.exit(0)
215