1 | --[[ |
2 | Message Translator |
3 | Made by Aim, updated by cli, Updated by rang#1234 |
4 | Credits to Riptxde for the sending chathook |
5 | --]] |
6 | syn = {request = request} |
7 | pcall(function() |
8 | if not game['Loaded'] then game['Loaded']:Wait() end; repeat wait(.06) until game:GetService('Players').LocalPlayer ~= nil |
9 | local YourLang = "en" -- Language code that the messages are going to be translated to |
10 | |
11 | local googlev = isfile'googlev.txt' and readfile'googlev.txt' or '' |
12 | |
13 | function googleConsent(Body) -- Because google really said: "Fuck you." |
14 | local args = {} |
15 | |
16 | for match in Body:gmatch('<input type="hidden" name=".-" value=".-">') do |
17 | local k,v = match:match('<input type="hidden" name="(.-)" value="(.-)">') |
18 | args[k] = v |
19 | end |
20 | googlev = args.v |
21 | writefile('googlev.txt', args.v) |
22 | end |
23 | |
24 | local function got(url, Method, Body) -- Basic version of https://www.npmjs.com/package/got using synapse's request API for google websites |
25 | Method = Method or "GET" |
26 | |
27 | local res = syn.request({ |
28 | Url = url, |
29 | Method = Method, |
30 | Headers = {cookie="CONSENT=YES+"..googlev}, |
31 | Body = Body |
32 | }) |
33 | |
34 | if res.Body:match('https://consent.google.com/s') then |
35 | print('consent') |
36 | googleConsent(res.Body) |
37 | res = syn.request({ |
38 | Url = url, |
39 | Method = "GET", |
40 | Headers = {cookie="CONSENT=YES+"..googlev} |
41 | }) |
42 | end |
43 | |
44 | return res |
45 | end |
46 | |
47 | local languages = { |
48 | auto = "Automatic", |
49 | af = "Afrikaans", |
50 | sq = "Albanian", |
51 | am = "Amharic", |
52 | ar = "Arabic", |
53 | hy = "Armenian", |
54 | az = "Azerbaijani", |
55 | eu = "Basque", |
56 | be = "Belarusian", |
57 | bn = "Bengali", |
58 | bs = "Bosnian", |
59 | bg = "Bulgarian", |
60 | ca = "Catalan", |
61 | ceb = "Cebuano", |
62 | ny = "Chichewa", |
63 | ['zh-cn'] = "Chinese Simplified", |
64 | ['zh-tw'] = "Chinese Traditional", |
65 | co = "Corsican", |
66 | hr = "Croatian", |
67 | cs = "Czech", |
68 | da = "Danish", |
69 | nl = "Dutch", |
70 | en = "English", |
71 | eo = "Esperanto", |
72 | et = "Estonian", |
73 | tl = "Filipino", |
74 | fi = "Finnish", |
75 | fr = "French", |
76 | fy = "Frisian", |
77 | gl = "Galician", |
78 | ka = "Georgian", |
79 | de = "German", |
80 | el = "Greek", |
81 | gu = "Gujarati", |
82 | ht = "Haitian Creole", |
83 | ha = "Hausa", |
84 | haw = "Hawaiian", |
85 | iw = "Hebrew", |
86 | hi = "Hindi", |
87 | hmn = "Hmong", |
88 | hu = "Hungarian", |
89 | is = "Icelandic", |
90 | ig = "Igbo", |
91 | id = "Indonesian", |
92 | ga = "Irish", |
93 | it = "Italian", |
94 | ja = "Japanese", |
95 | jw = "Javanese", |
96 | kn = "Kannada", |
97 | kk = "Kazakh", |
98 | km = "Khmer", |
99 | ko = "Korean", |
100 | ku = "Kurdish (Kurmanji)", |
101 | ky = "Kyrgyz", |
102 | lo = "Lao", |
103 | la = "Latin", |
104 | lv = "Latvian", |
105 | lt = "Lithuanian", |
106 | lb = "Luxembourgish", |
107 | mk = "Macedonian", |
108 | mg = "Malagasy", |
109 | ms = "Malay", |
110 | ml = "Malayalam", |
111 | mt = "Maltese", |
112 | mi = "Maori", |
113 | mr = "Marathi", |
114 | mn = "Mongolian", |
115 | my = "Myanmar (Burmese)", |
116 | ne = "Nepali", |
117 | no = "Norwegian", |
118 | ps = "Pashto", |
119 | fa = "Persian", |
120 | pl = "Polish", |
121 | pt = "Portuguese", |
122 | pa = "Punjabi", |
123 | ro = "Romanian", |
124 | ru = "Russian", |
125 | sm = "Samoan", |
126 | gd = "Scots Gaelic", |
127 | sr = "Serbian", |
128 | st = "Sesotho", |
129 | sn = "Shona", |
130 | sd = "Sindhi", |
131 | si = "Sinhala", |
132 | sk = "Slovak", |
133 | sl = "Slovenian", |
134 | so = "Somali", |
135 | es = "Spanish", |
136 | su = "Sundanese", |
137 | sw = "Swahili", |
138 | sv = "Swedish", |
139 | tg = "Tajik", |
140 | ta = "Tamil", |
141 | te = "Telugu", |
142 | th = "Thai", |
143 | tr = "Turkish", |
144 | uk = "Ukrainian", |
145 | ur = "Urdu", |
146 | uz = "Uzbek", |
147 | vi = "Vietnamese", |
148 | cy = "Welsh", |
149 | xh = "Xhosa", |
150 | yi = "Yiddish", |
151 | yo = "Yoruba", |
152 | zu = "Zulu" |
153 | }; |
154 | |
155 | function find(lang) |
156 | for i,v in pairs(languages) do |
157 | if i == lang or v == lang then |
158 | return i |
159 | end |
160 | end |
161 | end |
162 | |
163 | function isSupported(lang) |
164 | local key = find(lang) |
165 | return key and true or false |
166 | end |
167 | |
168 | function getISOCode(lang) |
169 | local key = find(lang) |
170 | return key |
171 | end |
172 | |
173 | function stringifyQuery(dataFields) |
174 | local data = "" |
175 | for k, v in pairs(dataFields) do |
176 | if type(v) == "table" then |
177 | for _,v in pairs(v) do |
178 | data = data .. ("&%s=%s"):format( |
179 | game.HttpService:UrlEncode(k), |
180 | game.HttpService:UrlEncode(v) |
181 | ) |
182 | end |
183 | else |
184 | data = data .. ("&%s=%s"):format( |
185 | game.HttpService:UrlEncode(k), |
186 | game.HttpService:UrlEncode(v) |
187 | ) |
188 | end |
189 | end |
190 | data = data:sub(2) |
191 | return data |
192 | end |
193 | |
194 | local reqid = math.random(1000,9999) |
195 | local rpcidsTranslate = "MkEWBc" |
196 | local rootURL = "https://translate.google.com/" |
197 | local executeURL = "https://translate.google.com/_/TranslateWebserverUi/data/batchexecute" |
198 | local fsid, bl |
199 | |
200 | do -- init |
201 | print('initialize') |
202 | local InitialReq = got(rootURL) |
203 | fsid = InitialReq.Body:match('"FdrFJe":"(.-)"') |
204 | bl = InitialReq.Body:match('"cfb2h":"(.-)"') |
205 | end |
206 | |
207 | local HttpService = game:GetService("HttpService") |
208 | function jsonE(o) |
209 | return HttpService:JSONEncode(o) |
210 | end |
211 | function jsonD(o) |
212 | return HttpService:JSONDecode(o) |
213 | end |
214 | |
215 | function translate(str, to, from) |
216 | reqid = reqid + 10000 |
217 | from = from and getISOCode(from) or 'auto' |
218 | to = to and getISOCode(to) or 'en' |
219 | |
220 | local data = {{str, from, to, true}, {nil}} |
221 | |
222 | local freq = { |
223 | { |
224 | { |
225 | rpcidsTranslate, |
226 | jsonE(data), |
227 | nil, |
228 | "generic" |
229 | } |
230 | } |
231 | } |
232 | |
233 | local url = executeURL..'?'..stringifyQuery{rpcids = rpcidsTranslate, ['f.sid'] = fsid, bl = bl, hl="en", _reqid = reqid-10000, rt = 'c'} |
234 | local body = stringifyQuery{['f.req'] = jsonE(freq)} |
235 | |
236 | local req = got(url, "POST", body) |
237 | |
238 | local body = jsonD(req.Body:match'%[.-%]\n') |
239 | local translationData = jsonD(body[1][3]) |
240 | local result = { |
241 | text = "", |
242 | from = { |
243 | language = "", |
244 | text = "" |
245 | }, |
246 | raw = "" |
247 | } |
248 | result.raw = translationData |
249 | result.text = translationData[2][1][1][6][1][1] |
250 | |
251 | result.from.language = translationData[3] |
252 | result.from.text = translationData[2][5][1] |
253 | |
254 | return result |
255 | end |
256 | |
257 | local Players = game:GetService("Players") |
258 | local LP = Players.LocalPlayer |
259 | local StarterGui = game:GetService('StarterGui') |
260 | for i=1, 15 do |
261 | local r = pcall(StarterGui["SetCore"]) |
262 | if r then break end |
263 | game:GetService('RunService').RenderStepped:wait() |
264 | end |
265 | wait() |
266 | |
267 | local properties = { |
268 | Color = Color3.new(1,1,0); |
269 | Font = Enum.Font.SourceSansItalic; |
270 | TextSize = 16; |
271 | } |
272 | |
273 | game:GetService("StarterGui"):SetCore("SendNotification", |
274 | { |
275 | Title = "Chat Translator", |
276 | Text = "Ported to Google Translate", |
277 | Duration = 3 |
278 | } |
279 | ) |
280 | |
281 | properties.Text = "[TR] To send messages in a language, say > followed by the target language/language code, e.g.: >ru or >russian. To disable (go back to original language), say >d." |
282 | StarterGui:SetCore("ChatMakeSystemMessage", properties) |
283 | |
284 | function translateFrom(message) |
285 | local translation = translate(message, YourLang) |
286 | |
287 | local text |
288 | if translation.from.language ~= YourLang then |
289 | text = translation.text |
290 | end |
291 | |
292 | return {text, translation.from.language} |
293 | end |
294 | |
295 | function get(plr, msg) |
296 | local tab = translateFrom(msg) |
297 | local translation = tab[1] |
298 | if translation then |
299 | properties.Text = "("..tab[2]:upper()..") ".."[".. plr.Name .."]: "..translation |
300 | StarterGui:SetCore("ChatMakeSystemMessage", properties) |
301 | end |
302 | end |
303 | |
304 | game.ReplicatedStorage.DefaultChatSystemChatEvents.OnMessageDoneFiltering.OnClientEvent:Connect(function(messageData) |
305 | get(game:GetService("Players")[messageData.FromSpeaker],messageData.Message) |
306 | end) |
307 | |
308 | local sendEnabled = false |
309 | local target = "" |
310 | |
311 | function translateTo(message, target) |
312 | target = target:lower() |
313 | local translation = translate(message, target, "auto") |
314 | |
315 | return translation.text |
316 | end |
317 | |
318 | function disableSend() |
319 | sendEnabled = false |
320 | properties.Text = "[TR] Sending Disabled" |
321 | StarterGui:SetCore("ChatMakeSystemMessage", properties) |
322 | end |
323 | |
324 | local CBar, CRemote, Connected = LP['PlayerGui']:WaitForChild('Chat')['Frame'].ChatBarParentFrame['Frame'].BoxFrame['Frame'].ChatBar, game:GetService('ReplicatedStorage').DefaultChatSystemChatEvents['SayMessageRequest'], {} |
325 | |
326 | local HookChat = function(Bar) |
327 | coroutine.wrap(function() |
328 | if not table.find(Connected,Bar) then |
329 | local Connect = Bar['FocusLost']:Connect(function(Enter) |
330 | if Enter ~= false and Bar['Text'] ~= '' then |
331 | local Message = Bar['Text'] |
332 | Bar['Text'] = ''; |
333 | if Message == ">d" then |
334 | disableSend() |
335 | elseif Message:sub(1,1) == ">" and not Message:find(" ") then |
336 | if getISOCode(Message:sub(2)) then |
337 | sendEnabled = true |
338 | target = Message:sub(2) |
339 | else |
340 | properties.Text = "[TR] Invalid language" |
341 | StarterGui:SetCore("ChatMakeSystemMessage", properties) |
342 | end |
343 | elseif sendEnabled then |
344 | Message = translateTo(Message, target) |
345 | if not _G.SecureChat then |
346 | game:GetService('Players'):Chat(Message); |
347 | end |
348 | CRemote:FireServer(Message,'All') |
349 | else |
350 | if not _G.SecureChat then |
351 | game:GetService('Players'):Chat(Message); |
352 | end |
353 | CRemote:FireServer(Message,'All') |
354 | end |
355 | end |
356 | end) |
357 | Connected[#Connected+1] = Bar; Bar['AncestryChanged']:Wait(); Connect:Disconnect() |
358 | end |
359 | end)() |
360 | end |
361 | |
362 | HookChat(CBar); local BindHook = Instance.new('BindableEvent') |
363 | |
364 | local MT = getrawmetatable(game); local NC = MT.__namecall; setreadonly(MT, false) |
365 | |
366 | MT.__namecall = newcclosure(function(...) |
367 | local Method, Args = getnamecallmethod(), {...} |
368 | if rawequal(tostring(Args[1]),'ChatBarFocusChanged') and rawequal(Args[2],true) then |
369 | if LP['PlayerGui']:FindFirstChild('Chat') then |
370 | BindHook:Fire() |
371 | end |
372 | end |
373 | return NC(...) |
374 | end) |
375 | |
376 | BindHook['Event']:Connect(function() |
377 | CBar = LP['PlayerGui'].Chat['Frame'].ChatBarParentFrame['Frame'].BoxFrame['Frame'].ChatBar |
378 | HookChat(CBar) |
379 | end) |
380 | end) |