· last year · Feb 12, 2024, 02:10 PM
1# -*- coding: utf-8 -*-
2import weechat as w
3import json
4
5SCRIPT_NAME = "translate"
6SCRIPT_AUTHOR = "Jerzy Dabrowski (kofany) <j@dabrowski.biz>"
7SCRIPT_VERSION = "1.0"
8SCRIPT_LICENSE = "GPL"
9SCRIPT_DESC = "Translates messages for specified channels and servers using Google Translate API."
10
11TRANSLATE_API_URL = "https://translation.googleapis.com/language/translate/v2"
12DETECT_API_URL = "https://translation.googleapis.com/language/translate/v2/detect"
13
14settings = {
15 "api_key": "",
16 "translate_channels_in": "{}",
17 "translate_channels_out": "{}",
18 "no_translate_lang": "pl", # Default language not to translate
19}
20
21translated_texts = {}
22
23def debug_print(buffer, message):
24 w.prnt(buffer, "DEBUG: " + message)
25
26def get_full_channel_name(channel, server):
27 full_channel_name = "{}@{}".format(channel, server)
28 debug_print("", f"[Translate Debug] Full channel name generated: {full_channel_name} from Channel: {channel}, Server: {server}")
29 return full_channel_name
30
31def api_request_cb(data, url, request, response):
32 debug_print("", f"[Translate Debug api_request_cb BEG] Current translated_texts content: {translated_texts}")
33 # Debugowanie danych wejściowych
34 debug_print("", "[Translate Debug] API request callback triggered.")
35 debug_print("", f"[Translate Debug] Input data: {data}")
36 debug_print("", f"[Translate Debug] URL: {url}")
37 debug_print("", f"[Translate Debug] Request: {request}")
38 debug_print("", f"[Translate Debug] Response: {response}")
39
40 callback_data = json.loads(data)
41 buffer = callback_data['buffer']
42 action = callback_data['action']
43 message_id = callback_data.get('message_id', '')
44 text_to_translate = callback_data.get('text', '') # Pobieramy tekst bezpośrednio z danych callback
45
46 debug_print("", f"[Translate Debug] Action: {action}")
47 debug_print("", f"[Translate Debug] Callback data: {callback_data}")
48
49 try:
50 response_data = json.loads(response['output'])
51 debug_print("", "[Translate Debug] Successfully parsed response data.")
52 except Exception as e:
53 debug_print(buffer, f"[Translate Debug] Error parsing response data: {e}")
54 return w.WEECHAT_RC_ERROR
55
56 if action == 'detect_and_translate':
57 if 'data' in response_data and 'detections' in response_data['data']:
58 detected_lang = response_data['data']['detections'][0][0]['language']
59 debug_print(buffer, f"[Translate Debug] Detected language: {detected_lang}")
60 target_lang = callback_data['target_lang']
61 if detected_lang != target_lang:
62 debug_print(buffer, "[Translate Debug] Detected language differs from target. Initiating translation.")
63 if text_to_translate:
64 # Wywołujemy funkcję translate z tekstem bezpośrednio
65 translate(buffer, detected_lang, target_lang, callback_data['api_key'], 'translate', message_id, text_to_translate)
66 else:
67 debug_print(buffer, f"[Translate Debug] No text found for message ID: {message_id}. Skipping translation.")
68 else:
69 debug_print(buffer, "[Translate Debug] Detected language is the same as target. No translation needed.")
70 else:
71 debug_print(buffer, "Error in response: No detections found")
72 elif action == 'translate':
73 if 'data' in response_data and 'translations' in response_data['data']:
74 translated_text = response_data['data']['translations'][0]['translatedText']
75 translated_texts[message_id] = translated_text # Aktualizujemy słownik, jeśli potrzebujemy zachować przetłumaczony tekst
76 debug_print(buffer, f"[Translate Debug] Translation completed: {translated_text}")
77 else:
78 debug_print(buffer, "Error in response: No translations found")
79 debug_print("", f"[Translate Debug api_request_cb END] Current translated_texts content: {translated_texts}")
80 return w.WEECHAT_RC_OK
81
82def translate(buffer, source_lang, target_lang, api_key, callback_action, message_id, text_to_translate):
83 debug_print("", f"[Translate Debug translate BEG] Current translated_texts content: {translated_texts}")
84 debug_print("", "[Translate Debug] Initiating translation process.")
85 if text_to_translate:
86 debug_print("", f"[Translate Debug] Text to translate (ID: {message_id}): {text_to_translate}")
87 else:
88 debug_print("", f"[Translate Debug] No text found for message ID: {message_id}. Skipping translation.")
89 return
90
91 debug_print("", f"[Translate Debug] Source language: {source_lang}, Target language: {target_lang}")
92 debug_print("", f"[Translate Debug] API Key: {'Present' if api_key else 'Not Present'}")
93
94 post_data = json.dumps({'q': text_to_translate, 'source': source_lang, 'target': target_lang, 'format': 'text'})
95 headers = "Content-Type: application/json\nx-goog-api-key: " + api_key
96 options = {"postfields": post_data, "httpheader": headers}
97 callback_data = json.dumps({
98 'buffer': buffer,
99 'action': callback_action,
100 'api_key': api_key,
101 'target_lang': target_lang,
102 'message_id': message_id
103 })
104
105 debug_print("", "[Translate Debug] Prepared request data for translation.")
106 debug_print("", f"[Translate Debug] Post data: {post_data}")
107 debug_print("", f"[Translate Debug] Headers: {headers}")
108 debug_print("", f"[Translate Debug] Callback data: {callback_data}")
109
110 w.hook_url(TRANSLATE_API_URL, options, 20000, "api_request_cb", callback_data)
111 debug_print("", "[Translate Debug] Hook URL called for translation.")
112 debug_print("", f"[Translate Debug translate END] Current translated_texts content: {translated_texts}")
113
114def detect_language_and_translate(buffer, message_id, text, server, channel, target_lang, api_key):
115 debug_print("", f"[Translate Debug detect_language_and_translate BEG] Current translated_texts content: {translated_texts}")
116 debug_print("", "[Translate Debug] Starting language detection and translation process.")
117 debug_print("", f"[Translate Debug] Text to detect and translate: {text}")
118 debug_print("", f"[Translate Debug] Target language: {target_lang}")
119 debug_print("", f"[Translate Debug] API Key: {'Present' if api_key else 'Not Present'}")
120 # Zapisz tekst przed wywołaniem detekcji
121 translated_texts[message_id] = text
122 post_data = json.dumps({'q': text})
123 headers = "Content-Type: application/json\nx-goog-api-key: " + api_key
124 options = {"postfields": post_data, "httpheader": headers}
125 callback_data = json.dumps({
126 'buffer': buffer,
127 'message_id': message_id,
128 'text': text,
129 'server': server,
130 'channel': channel,
131 'target_lang': target_lang,
132 'action': 'detect_and_translate',
133 'api_key': api_key
134 })
135 debug_print("", "[Translate Debug] Prepared request data for language detection and translation.")
136 debug_print("", f"[Translate Debug] Post data: {post_data}")
137 debug_print("", f"[Translate Debug] Headers: {headers}")
138 debug_print("", f"[Translate Debug] Callback data: {callback_data}")
139
140 w.hook_url(DETECT_API_URL, options, 20000, "api_request_cb", callback_data)
141 debug_print("", "[Translate Debug] Hook URL called for language detection and translation.")
142 debug_print("", f"[Translate Debug detect_language_and_translate END] Current translated_texts content: {translated_texts}")
143
144def translate_incoming_message_cb(data, modifier, modifier_data, string):
145 debug_print("", f"[Translate Debug translate_incoming_message_cb BEG] Current translated_texts content: {translated_texts}")
146 api_key = w.config_get_plugin("api_key")
147 if not api_key:
148 debug_print("", "[Translate Debug] API key is not set.")
149 return string
150
151 parsed_data = w.info_get_hashtable("irc_message_parse", {"message": string})
152 channel = parsed_data["channel"]
153 message = parsed_data["text"]
154 server = modifier_data
155 message_id = str(hash(message)) # Unique ID for the message
156
157 debug_print("", f"[Translate Debug] Received message: {message}")
158 debug_print("", f"[Translate Debug] Channel: {channel}, Server: {server}")
159 debug_print("", f"[Translate Debug] Message ID: {message_id}")
160
161 full_channel_name = get_full_channel_name(channel, server)
162 translate_channels_in = json.loads(w.config_get_plugin("translate_channels_in"))
163
164 debug_print("", f"[Translate Debug] Full channel name: {full_channel_name}")
165 debug_print("", f"[Translate Debug] Translate channels in: {translate_channels_in}")
166
167 if full_channel_name in translate_channels_in:
168 target_lang = translate_channels_in[full_channel_name]
169 debug_print("", f"[Translate Debug] Target language for translation: {target_lang}")
170 translated_texts[message_id] = message # Store original message for translation
171 detect_language_and_translate("", message_id, message, server, channel, target_lang, api_key)
172 else:
173 debug_print("", "[Translate Debug] Channel not in translate_channels_in list.")
174
175 # Check if translated text is available and replace original message
176 if message_id in translated_texts:
177 translated_message = translated_texts.pop(message_id)
178 debug_print("", f"[Translate Debug] Translated message: {translated_message}")
179 return string.replace(message, translated_message)
180 else:
181 debug_print("", "[Translate Debug] Translated message not available yet.")
182 debug_print("", f"[Translate Debug translate_incoming_message_cb BEG] Current translated_texts content: {translated_texts}")
183 return string
184
185def translate_command_cb(data, buffer, args):
186 argv = args.split(" ")
187 command = argv[0] if len(argv) > 0 else ""
188
189 if command == "list":
190 translate_channels_in = json.loads(w.config_get_plugin("translate_channels_in"))
191 translate_channels_out = json.loads(w.config_get_plugin("translate_channels_out"))
192 w.prnt(buffer, "Channels for incoming translation:")
193 for channel, lang in translate_channels_in.items():
194 w.prnt(buffer, " {} -> {}".format(channel, lang))
195 w.prnt(buffer, "Channels for outgoing translation:")
196 for channel, lang in translate_channels_out.items():
197 w.prnt(buffer, " {} -> {}".format(channel, lang))
198 elif command in ["addin", "addout"]:
199 if len(argv) != 4:
200 w.prnt(buffer, "Usage: /translate addin|addout <server> <channel> <target_lang>")
201 return w.WEECHAT_RC_ERROR
202 server_channel = get_full_channel_name(argv[2], argv[1])
203 target_lang = argv[3]
204 translate_channels = json.loads(w.config_get_plugin("translate_channels_in" if command == "addin" else "translate_channels_out"))
205 translate_channels[server_channel] = target_lang
206 w.config_set_plugin("translate_channels_in" if command == "addin" else "translate_channels_out", json.dumps(translate_channels))
207 w.prnt(buffer, "{} added for {} translation to {}.".format(server_channel, "incoming" if command == "addin" else "outgoing", target_lang))
208 elif command in ["delin", "delout"]:
209 if len(argv) != 3:
210 w.prnt(buffer, "Usage: /translate delin|delout <server> <channel>")
211 return w.WEECHAT_RC_ERROR
212 server_channel = get_full_channel_name(argv[2], argv[1])
213 translate_channels = json.loads(w.config_get_plugin("translate_channels_in" if command == "delin" else "translate_channels_out"))
214 if server_channel in translate_channels:
215 del translate_channels[server_channel]
216 w.config_set_plugin("translate_channels_in" if command == "delin" else "translate_channels_out", json.dumps(translate_channels))
217 w.prnt(buffer, "{} removed from {} translation.".format(server_channel, "incoming" if command == "delin" else "outgoing"))
218 else:
219 w.prnt(buffer, "{} not found in {} translation settings.".format(server_channel, "incoming" if command == "delin" else "outgoing"))
220
221 elif command == "code":
222 magenta = w.color("magenta")
223 reset = w.color("reset")
224 codes = [
225 ("Azerbaijani", "az"), ("Hausa", "ha"), ("Malay", "ms"), ("Spanish", "es"),
226 ("Bambara", "bm"), ("Hawaiian", "haw"), ("Malayalam", "ml"), ("Sundanese", "su"),
227 ("Basque", "eu"), ("Hebrew", "he"), ("Maltese", "mt"), ("Swahili", "sw"),
228 ("Belarusian", "be"), ("Hindi", "hi"), ("Maori", "mi"), ("Swedish", "sv"),
229 ("Bengali", "bn"), ("Hmong", "hmn"), ("Marathi", "mr"), ("Tagalog", "tl"),
230 ("Bhojpuri", "bho"), ("Hungarian", "hu"), ("Meiteilon", "mni"), ("Tajik", "tg"),
231 ("Bosnian", "bs"), ("Icelandic", "is"), ("Mizo (lus)", "lus"), ("Tamil", "ta"),
232 ("Bulgarian", "bg"), ("Igbo", "ig"), ("Mongolian", "mn"), ("Tatar", "tt"),
233 ("Catalan", "ca"), ("Ilocano (ilo)", "ilo"), ("Myanmar (my)", "my"), ("Telugu", "te"),
234 ("Cebuano", "ceb"), ("Indonesian", "id"), ("Nepali", "ne"), ("Thai", "th"),
235 ("Chinese (Simpl)", "zh-CN"), ("Irish", "ga"), ("Norwegian", "no"), ("Tigrinya", "ti"),
236 ("Chinese (Trad)", "zh-TW"), ("Italian", "it"), ("Nyanja (ny)", "ny"), ("Tsonga", "ts"),
237 ("Corsican", "co"), ("Japanese", "ja"), ("Odia (or)", "or"), ("Turkish", "tr"),
238 ("Croatian", "hr"), ("Javanese", "jv"), ("Oromo (om)", "om"), ("Turkmen", "tk"),
239 ("Czech", "cs"), ("Kannada", "kn"), ("Pashto", "ps"), ("Twi (ak)", "ak"),
240 ("Danish", "da"), ("Kazakh", "kk"), ("Persian", "fa"), ("Ukrainian", "uk"),
241 ("Dhivehi", "dv"), ("Khmer", "km"), ("Polish", "pl"), ("Urdu", "ur"),
242 ("Dogri (doi)", "doi"), ("Kinyarwanda", "rw"), ("Portuguese", "pt"), ("Uyghur", "ug"),
243 ("Dutch", "nl"), ("Konkani (gom)", "gom"), ("Punjabi", "pa"), ("Uzbek", "uz"),
244 ("English", "en"), ("Korean", "ko"), ("Quechua", "qu"), ("Vietnamese", "vi"),
245 ("Esperanto", "eo"), ("Krio (kri)", "kri"), ("Romanian", "ro"), ("Welsh", "cy"),
246 ("Estonian", "et"), ("Kurdish", "ku"), ("Russian", "ru"), ("Xhosa", "xh"),
247 ("Ewe", "ee"), ("Kurdish (ckb)", "ckb"), ("Samoan", "sm"), ("Yiddish", "yi"),
248 ("Filipino", "fil"), ("Kyrgyz", "ky"), ("Sanskrit", "sa"), ("Yoruba", "yo"),
249 ("Finnish", "fi"), ("Lao", "lo"), ("Scots (gd)", "gd"), ("Zulu", "zu"),
250 ("French", "fr"), ("Latin", "la"), ("Sepedi (nso)", "nso"),
251 ("Frisian", "fy"), ("Latvian", "lv"), ("Serbian", "sr"),
252 ]
253 w.prnt("", "Available language codes:")
254 column_width = 20
255 for i in range(0, len(codes), 4):
256 line = "".join(f"{name.ljust(column_width - len(code))}{magenta}{code}{reset} " for name, code in codes[i:i+4])
257 w.prnt(buffer, line)
258
259 elif command == "help":
260 w.prnt(buffer, "/translate command usage:")
261 w.prnt(buffer, "/translate list - Show all channels with translation settings")
262 w.prnt(buffer, "/translate addin <server> <channel> <target_lang> - Add a channel to translate incoming messages")
263 w.prnt(buffer, "/translate addout <server> <channel> <target_lang> - Add a channel to translate outgoing messages")
264 w.prnt(buffer, "/translate delin <server> <channel> - Remove a channel from translating incoming messages")
265 w.prnt(buffer, "/translate delout <server> <channel> - Remove a channel from translating outgoing messages")
266 w.prnt(buffer, "/translate code - Show available language codes for translation")
267 w.prnt(buffer, "/translate help - Show this help message")
268
269 else:
270 w.prnt(buffer, "Unknown command. Use /translate help for usage information.")
271
272 return w.WEECHAT_RC_OK
273
274if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
275 for option, default_value in settings.items():
276 if not w.config_is_set_plugin(option):
277 w.config_set_plugin(option, default_value)
278 w.hook_modifier("irc_in_privmsg", "translate_incoming_message_cb", "")
279 w.hook_command("translate", "Manage translation settings",
280 "list | addin <server> <channel> <target_lang> | addout <server> <channel> <target_lang> | delin <server> <channel> | delout <server> <channel> | code | help",
281 "list: show all channels with translation settings\n"
282 "addin: add a channel to translate incoming messages\n"
283 "addout: add a channel to translate outgoing messages\n"
284 "delin: remove a channel from translating incoming messages\n"
285 "delout: remove a channel from translating outgoing messages\n"
286 "code: show available language codes for translation\n"
287 "help: show help information for the /translate command\n",
288 "list || addin %(irc_servers) %(irc_channels) || addout %(irc_servers) %(irc_channels) || delin %(irc_servers) %(irc_channels) || delout %(irc_servers) %(irc_channels) || code || help",
289 "translate_command_cb", "")