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