qiell

Translate

Nov 4th, 2025 (edited)
11
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.44 KB | None | 0 0
  1. --[[
  2. All-in-One Chat Translator with UI (Compact & Searchable Version)
  3. - Translates outgoing messages to a selected language or into a "Jumble" mode.
  4. - Translates incoming messages into English.
  5. - Features a compact, draggable, and collapsible UI with 100 languages
  6. visually separated by category.
  7. - NEW: Includes a search bar to instantly filter the language list.
  8. --]]
  9.  
  10. -- Wait for the game to be fully loaded.
  11. if not game:IsLoaded() then game.Loaded:Wait() end
  12. repeat task.wait(.06) until game:GetService("Players").LocalPlayer
  13.  
  14. -- Services
  15. local Http = game:GetService("HttpService")
  16. local Players = game:GetService("Players")
  17. local TCS = game:GetService("TextChatService")
  18. local CoreGui = game:GetService("CoreGui")
  19. local UserInputService = game:GetService("UserInputService")
  20. local LP = Players.LocalPlayer
  21.  
  22. -- Translator State
  23. local isTranslatorActive = false -- Translator is disabled by default.
  24. local isJumbleActive = false -- Jumble mode is disabled by default.
  25. local yourLanguage = "en" -- Language for incoming messages.
  26. local targetLanguage = nil -- Target language for your outgoing messages (starts as none).
  27.  
  28. -- A structured array of tables,
  29. -- This new structure allows us. to build the UI in a specific order.
  30. local languageCategories = {
  31. {
  32. Name = "Global & Constructed",
  33. Languages = {
  34. ["English (USA/UK)"] = "en",
  35. ["Esperanto (Global)"] = "eo",
  36. ["Latin (Global)"] = "la"
  37. }
  38. },
  39. {
  40. Name = "African Languages",
  41. Languages = {
  42. ["Afrikaans (South Africa)"] = "af",
  43. ["Amharic (Ethiopia)"] = "am",
  44. ["Hausa (Nigeria)"] = "ha",
  45. ["Igbo (Nigeria)"] = "ig",
  46. ["Malagasy (Madagascar)"] = "mg",
  47. ["Sesotho (Lesotho)"] = "st",
  48. ["Shona (Zimbabwe)"] = "sn",
  49. ["Somali (Somalia)"] = "so",
  50. ["Swahili (Tanzania/Kenya)"] = "sw",
  51. ["Xhosa (South Africa)"] = "xh",
  52. ["Yoruba (Nigeria)"] = "yo",
  53. ["Zulu (South Africa)"] = "zu"
  54. }
  55. },
  56. {
  57. Name = "Asian Languages",
  58. Languages = {
  59. ["Armenian (Armenia)"] = "hy",
  60. ["Azerbaijani (Azerbaijan)"] = "az",
  61. ["Bengali (Bangladesh)"] = "bn",
  62. ["Burmese (Myanmar)"] = "my",
  63. ["Chinese (China)"] = "zh-cn",
  64. ["Georgian (Georgia)"] = "ka",
  65. ["Gujarati (India)"] = "gu",
  66. ["Hindi (India)"] = "hi",
  67. ["Hmong (China/Vietnam)"] = "hmn",
  68. ["Indonesian (Indonesia)"] = "id",
  69. ["Japanese (Japan)"] = "ja",
  70. ["Javanese (Indonesia)"] = "jw",
  71. ["Kannada (India)"] = "kn",
  72. ["Kazakh (Kazakhstan)"] = "kk",
  73. ["Khmer (Cambodia)"] = "km",
  74. ["Korean (South Korea)"] = "ko",
  75. ["Kurdish (Kurdistan)"] = "ku",
  76. ["Kyrgyz (Kyrgyzstan)"] = "ky",
  77. ["Lao (Laos)"] = "lo",
  78. ["Malay (Malaysia)"] = "ms",
  79. ["Malayalam (India)"] = "ml",
  80. ["Marathi (India)"] = "mr",
  81. ["Mongolian (Mongolia)"] = "mn",
  82. ["Nepali (Nepal)"] = "ne",
  83. ["Pashto (Afghanistan)"] = "ps",
  84. ["Punjabi (India/Pakistan)"] = "pa",
  85. ["Sindhi (Pakistan)"] = "sd",
  86. ["Sinhala (Sri Lanka)"] = "si",
  87. ["Sundanese (Indonesia)"] = "su",
  88. ["Tajik (Tajikistan)"] = "tg",
  89. ["Tamil (India/Sri Lanka)"] = "ta",
  90. ["Telugu (India)"] = "te",
  91. ["Thai (Thailand)"] = "th",
  92. ["Urdu (Pakistan/India)"] = "ur",
  93. ["Uzbek (Uzbekistan)"] = "uz",
  94. ["Vietnamese (Vietnam)"] = "vi"
  95. }
  96. },
  97. {
  98. Name = "European Languages",
  99. Languages = {
  100. ["Albanian (Albania)"] = "sq",
  101. ["Basque (Spain/France)"] = "eu",
  102. ["Belarusian (Belarus)"] = "be",
  103. ["Bosnian (Bosnia)"] = "bs",
  104. ["Bulgarian (Bulgaria)"] = "bg",
  105. ["Catalan (Spain)"] = "ca",
  106. ["Corsican (France)"] = "co",
  107. ["Croatian (Croatia)"] = "hr",
  108. ["Czech (Czechia)"] = "cs",
  109. ["Danish (Denmark)"] = "da",
  110. ["Dutch (Netherlands)"] = "nl",
  111. ["Estonian (Estonia)"] = "et",
  112. ["Finnish (Finland)"] = "fi",
  113. ["French (France/Canada)"] = "fr",
  114. ["Frisian (Netherlands)"] = "fy",
  115. ["Galician (Spain)"] = "gl",
  116. ["German (Germany)"] = "de",
  117. ["Greek (Greece)"] = "el",
  118. ["Hungarian (Hungary)"] = "hu",
  119. ["Icelandic (Iceland)"] = "is",
  120. ["Irish (Ireland)"] = "ga",
  121. ["Italian (Italy)"] = "it",
  122. ["Latvian (Latvia)"] = "lv",
  123. ["Lithuanian (Lithuania)"] = "lt",
  124. ["Luxembourgish (Luxembourg)"] = "lb",
  125. ["Macedonian (N. Macedonia)"] = "mk",
  126. ["Maltese (Malta)"] = "mt",
  127. ["Norwegian (Norway)"] = "no",
  128. ["Polish (Poland)"] = "pl",
  129. ["Portuguese (Portugal/Brazil)"] = "pt",
  130. ["Romanian (Romania)"] = "ro",
  131. ["Russian (Russia)"] = "ru",
  132. ["Scots Gaelic (Scotland)"] = "gd",
  133. ["Serbian (Serbia)"] = "sr",
  134. ["Slovak (Slovakia)"] = "sk",
  135. ["Slovenian (Slovenia)"] = "sl",
  136. ["Spanish (Spain/Mexico)"] = "es",
  137. ["Swedish (Sweden)"] = "sv",
  138. ["Ukrainian (Ukraine)"] = "uk",
  139. ["Welsh (Wales)"] = "cy"
  140. }
  141. },
  142. {
  143. Name = "Middle Eastern Languages",
  144. Languages = {
  145. ["Arabic (Saudi Arabia)"] = "ar",
  146. ["Hebrew (Israel)"] = "iw",
  147. ["Persian (Iran)"] = "fa",
  148. ["Turkish (Turkey)"] = "tr",
  149. ["Yiddish (Israel/USA)"] = "yi"
  150. }
  151. },
  152. {
  153. Name = "North & Central American",
  154. Languages = {
  155. ["Haitian Creole (Haiti)"] = "ht"
  156. }
  157. },
  158. {
  159. Name = "Oceanian Languages",
  160. Languages = {
  161. ["Cebuano (Philippines)"] = "ceb",
  162. ["Filipino (Philippines)"] = "tl",
  163. ["Hawaiian (USA)"] = "haw",
  164. ["Maori (New Zealand)"] = "mi",
  165. ["Samoan (Samoa)"] = "sm"
  166. }
  167. }
  168. }
  169.  
  170. -- Create flat tables for the existing logic to use.
  171. -- 'languages' maps the full name "Language (Country)" to its code "lg".
  172. -- 'langCodesArray' is just a list of all codes for Jumble mode.
  173. local languages = {}
  174. local langCodesArray = {}
  175.  
  176. for _, categoryData in ipairs(languageCategories) do
  177. for langName, langCode in pairs(categoryData.Languages) do
  178. languages[langName] = langCode
  179. table.insert(langCodesArray, langCode)
  180. end
  181. end
  182.  
  183. --region Translation API Functions
  184. -- This section handles the connection to the translation service.
  185.  
  186. local gv -- Google consent value.
  187. local function req(opt)
  188. local fn = (syn and syn.request) or (http and http.request) or http_request or request
  189. if fn then return fn(opt) end
  190. return Http:RequestAsync(opt)
  191. end
  192.  
  193. local function consent(body)
  194. local t = {}
  195. for tag in body:gmatch('<input type="hidden" name=".-" value=".-">') do
  196. local k, v = tag:match('<input type="hidden" name="(.-)" value="(.-)">')
  197. t[k] = v
  198. end
  199. gv = t.v or ""
  200. end
  201.  
  202. local function got(url, method, body)
  203. method = method or "GET"
  204. local res = req({Url = url, Method = method, Headers = {cookie = "CONSENT=YES+" .. (gv or "")}, Body = body})
  205. local b = res.Body or res.body or ""
  206. if type(b) ~= "string" then b = tostring(b) end
  207. if b:match("https://consent.google.com/s") then
  208. consent(b)
  209. res = req({Url = url, Method = "GET", Headers = {cookie = "CONSENT=YES+" .. (gv or "")}})
  210. end
  211. return res
  212. end
  213.  
  214. local function q(data)
  215. local s = ""
  216. for k, v in pairs(data) do
  217. if type(v) == "table" then
  218. for _, vv in pairs(v) do s ..= "&" .. Http:UrlEncode(k) .. "=" .. Http:UrlEncode(vv) end
  219. else
  220. s ..= "&" .. Http:UrlEncode(k) .. "=" .. Http:UrlEncode(v)
  221. end
  222. end
  223. return s:sub(2)
  224. end
  225.  
  226. local jE = function(x) return Http:JSONEncode(x) end
  227. local jD = function(x) return Http:JSONDecode(x) end
  228.  
  229. local rpc = "MkEWBc"
  230. local root = "https://translate.google.com/"
  231. local exec = "https://translate.google.com/_/TranslateWebserverUi/data/batchexecute"
  232.  
  233. local fsid, bl, rid = nil, nil, math.random(1000, 9999)
  234. do
  235. local b = (got(root).Body or "")
  236. fsid = b:match('"FdrFJe":"(.-)"')
  237. bl = b:match('"cfb2h":"(.-)"')
  238. end
  239.  
  240. local function translate(txt, tgt, src)
  241. rid += 10000
  242. src = src or "auto"
  243. local data = {{txt, src, tgt, true}, {nil}}
  244. local freq = {{{rpc, jE(data), nil, "generic"}}}
  245. local url = exec .. "?" .. q{rpcids = rpc, ["f.sid"] = fsid, bl = bl, hl = "en", _reqID = rid - 10000, rt = "c"}
  246. local body = q{["f.req"] = jE(freq)}
  247. local res = got(url, "POST", body)
  248. local ok, out = pcall(function()
  249. local arr = jD((res.Body or ""):match("%[.-%]\n"))
  250. return jD(arr[1][3])
  251. end)
  252. if not ok then return nil end
  253. return out[2][1][1][6][1][1]
  254. end
  255.  
  256. local function translateInfo(txt, tgt, src)
  257. rid += 10000
  258. src = src or "auto"
  259. local data = {{txt, src, tgt, true}, {nil}}
  260. local freq = {{{rpc, jE(data), nil, "generic"}}}
  261. local url = exec .. "?" .. q{rpcids = rpc, ["f.sid"] = fsid, bl = bl, hl = "en", _reqID = rid - 10000, rt = "c"}
  262. local body = q{["f.req"] = jE(freq)}
  263. local res = got(url, "POST", body)
  264. local ok, out = pcall(function()
  265. local arr = jD((res.Body or ""):match("%[.-%]\n"))
  266. return jD(arr[1][3])
  267. end)
  268. if not ok or not out then return nil, nil end
  269. return out[2][1][1][6][1][1], out[3]
  270. end
  271.  
  272. --endregion
  273.  
  274. --region Chat Helper Functions
  275. -- This section manages sending messages and interacting with the chat UI.
  276.  
  277. local function sys(msg)
  278. local chans = TCS:WaitForChild("TextChannels", 60)
  279. if not chans then return end
  280. local c = chans:FindFirstChild("RBXSystem") or chans:FindFirstChild("RBXGeneral") or chans:GetChildren()[1]
  281. if c and c.DisplaySystemMessage then
  282. c:DisplaySystemMessage(msg)
  283. end
  284. end
  285.  
  286. local function defaultChannel()
  287. return TCS.TextChannels:FindFirstChild("RBXGeneral") or TCS.TextChannels:FindFirstChild("General") or TCS.TextChannels:FindFirstChild("RBXSystem")
  288. end
  289.  
  290. local function sendChat(text)
  291. task.spawn(function()
  292. local chan = defaultChannel()
  293. if chan then
  294. chan:SendAsync(text)
  295. end
  296. end)
  297. end
  298.  
  299. -- This function intercepts your outgoing chat messages to perform translation.
  300. local function handleOutgoing(rawMessage)
  301. -- Ignore commands (e.g., /w, /team).
  302. if rawMessage:sub(1, 1) == "/" then return false end
  303.  
  304. -- Jumble mode is for fun. It translates each word separately into a random language.
  305. -- This mode intentionally breaks grammar and punctuation.
  306. if isJumbleActive then
  307. local words = {}
  308. for word in rawMessage:gmatch("%S+") do
  309. table.insert(words, word)
  310. end
  311.  
  312. local translatedWords = {}
  313. for _, word in ipairs(words) do
  314. local randomLangCode = langCodesArray[math.random(#langCodesArray)]
  315. local translatedWord = translate(word, randomLangCode, "auto") or word
  316. table.insert(translatedWords, translatedWord)
  317. end
  318.  
  319. sendChat(table.concat(translatedWords, " "))
  320. return true
  321.  
  322. -- Standard translator mode.
  323. elseif isTranslatorActive and targetLanguage then
  324. -- The entire message (rawMessage) is sent to the translation function.
  325. -- This provides context, allowing the API to handle grammar, word order, and
  326. -- punctuation correctly, resulting in a much more natural and accurate translation.
  327. local translatedText = translate(rawMessage, targetLanguage, "auto") or rawMessage
  328. sendChat(translatedText)
  329. return true
  330. end
  331.  
  332. -- If the translator is off, the message is sent normally.
  333. return false
  334. end
  335.  
  336. --endregion
  337.  
  338. --region UI Creation
  339. -- This section creates the graphical user interface.
  340.  
  341. local screenGui = Instance.new("ScreenGui")
  342. screenGui.Name = "TranslatorUI"
  343. screenGui.Parent = CoreGui
  344. screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
  345.  
  346. local mainFrame = Instance.new("Frame")
  347. mainFrame.Name = "MainFrame"
  348. mainFrame.Parent = screenGui
  349. mainFrame.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
  350. mainFrame.BorderColor3 = Color3.fromRGB(80, 80, 80)
  351. mainFrame.BorderSizePixel = 1
  352. mainFrame.Position = UDim2.new(0, 20, 0, 20)
  353. mainFrame.Size = UDim2.new(0, 280, 0, 30)
  354. mainFrame.ClipsDescendants = true
  355. mainFrame.Active = true
  356. mainFrame.Draggable = true
  357.  
  358. local titleLabel = Instance.new("TextLabel")
  359. titleLabel.Name = "Title"
  360. titleLabel.Parent = mainFrame
  361. titleLabel.BackgroundTransparency = 1
  362. titleLabel.Position = UDim2.new(0, 10, 0, 0)
  363. titleLabel.Size = UDim2.new(0, 100, 0, 30)
  364. titleLabel.Font = Enum.Font.SourceSansBold
  365. titleLabel.Text = "Translator"
  366. titleLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
  367. titleLabel.TextSize = 16
  368. titleLabel.TextXAlignment = Enum.TextXAlignment.Left
  369.  
  370. local toggleButton = Instance.new("TextButton")
  371. toggleButton.Name = "ToggleButton"
  372. toggleButton.Parent = mainFrame
  373. toggleButton.BackgroundColor3 = Color3.fromRGB(55, 55, 55)
  374. toggleButton.Size = UDim2.new(0, 25, 0, 20)
  375. toggleButton.Position = UDim2.new(1, -30, 0.5, -10)
  376. toggleButton.Font = Enum.Font.SourceSansBold
  377. toggleButton.Text = "[+]"
  378. toggleButton.TextColor3 = Color3.fromRGB(200, 200, 200)
  379. toggleButton.TextSize = 16
  380. toggleButton.ZIndex = 2
  381.  
  382. local scrollFrame = Instance.new("ScrollingFrame")
  383. scrollFrame.Name = "ScrollFrame"
  384. scrollFrame.Parent = mainFrame
  385. scrollFrame.BackgroundTransparency = 1
  386. scrollFrame.Position = UDim2.new(0, 0, 0, 30)
  387. scrollFrame.Size = UDim2.new(1, 0, 1, -30)
  388. scrollFrame.Visible = false
  389. scrollFrame.ZIndex = 1
  390. scrollFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y
  391. scrollFrame.ScrollBarImageColor3 = Color3.fromRGB(120, 120, 120)
  392. scrollFrame.ScrollBarThickness = 6
  393. scrollFrame.BorderSizePixel = 0
  394.  
  395. local listLayout = Instance.new("UIListLayout")
  396. listLayout.Parent = scrollFrame
  397. listLayout.SortOrder = Enum.SortOrder.LayoutOrder
  398. listLayout.Padding = UDim.new(0, 5)
  399.  
  400. local controlFrame = Instance.new("Frame")
  401. controlFrame.Name = "ControlFrame"
  402. controlFrame.Parent = scrollFrame
  403. controlFrame.BackgroundTransparency = 1
  404. controlFrame.Size = UDim2.new(1, 0, 0, 30) -- Height for one row of buttons
  405. controlFrame.AutomaticSize = Enum.AutomaticSize.Y
  406. controlFrame.LayoutOrder = 1 -- Place this at the top.
  407.  
  408. local controlGrid = Instance.new("UIGridLayout")
  409. controlGrid.Parent = controlFrame
  410. controlGrid.CellPadding = UDim2.new(0, 5, 0, 5)
  411. controlGrid.CellSize = UDim2.new(0, 85, 0, 25)
  412. controlGrid.StartCorner = Enum.StartCorner.TopLeft
  413. controlGrid.HorizontalAlignment = Enum.HorizontalAlignment.Center
  414. controlGrid.SortOrder = Enum.SortOrder.LayoutOrder
  415.  
  416. local stopButton = Instance.new("TextButton")
  417. stopButton.Name = "StopButton"
  418. stopButton.Parent = controlFrame
  419. stopButton.BackgroundColor3 = Color3.fromRGB(150, 40, 40)
  420. stopButton.BorderColor3 = Color3.fromRGB(80, 80, 80)
  421. stopButton.Font = Enum.Font.SourceSansBold
  422. stopButton.Text = "Stop"
  423. stopButton.TextColor3 = Color3.fromRGB(255, 255, 255)
  424. stopButton.TextSize = 14
  425. stopButton.LayoutOrder = 1 -- First item in this grid.
  426.  
  427. local jumbleButton = Instance.new("TextButton")
  428. jumbleButton.Name = "JumbleButton"
  429. jumbleButton.Parent = controlFrame
  430. jumbleButton.BackgroundColor3 = Color3.fromRGB(120, 60, 180) -- A unique purple color.
  431. jumbleButton.BorderColor3 = Color3.fromRGB(80, 80, 80)
  432. jumbleButton.Font = Enum.Font.SourceSansBold
  433. jumbleButton.Text = "Jumble"
  434. jumbleButton.TextColor3 = Color3.fromRGB(255, 255, 255)
  435. jumbleButton.TextSize = 14
  436. jumbleButton.LayoutOrder = 2 -- Second item in this grid.
  437.  
  438. -- NEW: Add a search bar
  439. local searchBoxFrame = Instance.new("Frame")
  440. searchBoxFrame.Name = "SearchBoxFrame"
  441. searchBoxFrame.Parent = scrollFrame
  442. searchBoxFrame.BackgroundTransparency = 1
  443. searchBoxFrame.Size = UDim2.new(1, -10, 0, 25)
  444. searchBoxFrame.Position = UDim2.new(0, 5, 0, 0)
  445. searchBoxFrame.LayoutOrder = 2 -- Place it after controls.
  446.  
  447. local searchBoxLabel = Instance.new("TextLabel")
  448. searchBoxLabel.Name = "SearchLabel"
  449. searchBoxLabel.Parent = searchBoxFrame
  450. searchBoxLabel.BackgroundTransparency = 1
  451. searchBoxLabel.Size = UDim2.new(0, 60, 1, 0)
  452. searchBoxLabel.Font = Enum.Font.SourceSans
  453. searchBoxLabel.Text = "Search: "
  454. searchBoxLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
  455. searchBoxLabel.TextSize = 14
  456. searchBoxLabel.TextXAlignment = Enum.TextXAlignment.Left
  457.  
  458. local searchBox = Instance.new("TextBox")
  459. searchBox.Name = "SearchBox"
  460. searchBox.Parent = searchBoxFrame
  461. searchBox.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
  462. searchBox.BorderColor3 = Color3.fromRGB(80, 80, 80)
  463. searchBox.Position = UDim2.new(0, 60, 0, 0)
  464. searchBox.Size = UDim2.new(1, -65, 1, 0)
  465. searchBox.Font = Enum.Font.SourceSans
  466. searchBox.Text = ""
  467. searchBox.TextColor3 = Color3.fromRGB(240, 240, 240)
  468. searchBox.TextSize = 14
  469. searchBox.PlaceholderText = "Type to filter..."
  470. searchBox.PlaceholderColor3 = Color3.fromRGB(150, 150, 150)
  471. searchBox.ClearTextOnFocus = false
  472.  
  473. -- This table will store all button instances for the click logic.
  474. local langButtons = {}
  475. -- NEW: This table stores UI elements by category for filtering.
  476. local categoryElements = {}
  477. local categoryLayoutOrder = 3 -- Start after the control frame and search bar.
  478.  
  479. -- CHANGE: Loop through the new 'languageCategories' array to build the UI.
  480. for _, categoryData in ipairs(languageCategories) do
  481.  
  482. -- 1. Create the Category Header (e.g., "Asian Languages")
  483. local headerLabel = Instance.new("TextLabel")
  484. headerLabel.Name = categoryData.Name .. "Header"
  485. headerLabel.Parent = scrollFrame
  486. headerLabel.BackgroundTransparency = 1
  487. headerLabel.Size = UDim2.new(1, -10, 0, 20)
  488. headerLabel.Position = UDim2.new(0, 5, 0, 0)
  489. headerLabel.Font = Enum.Font.SourceSansBold
  490. headerLabel.Text = categoryData.Name
  491. headerLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
  492. headerLabel.TextSize = 16
  493. headerLabel.TextXAlignment = Enum.TextXAlignment.Left
  494. headerLabel.LayoutOrder = categoryLayoutOrder
  495. categoryLayoutOrder += 1
  496.  
  497. -- 2. Create a container Frame for this category's buttons
  498. local buttonContainer = Instance.new("Frame")
  499. buttonContainer.Name = categoryData.Name .. "Container"
  500. buttonContainer.Parent = scrollFrame
  501. buttonContainer.BackgroundTransparency = 1
  502. buttonContainer.Size = UDim2.new(1, 0, 0, 50) -- Height will be set by AutomaticSize
  503. buttonContainer.AutomaticSize = Enum.AutomaticSize.Y
  504. buttonContainer.LayoutOrder = categoryLayoutOrder
  505. categoryLayoutOrder += 1
  506.  
  507. -- 3. Add a UIGridLayout to this specific container
  508. local gridLayout = Instance.new("UIGridLayout")
  509. gridLayout.Parent = buttonContainer
  510. gridLayout.CellPadding = UDim2.new(0, 5, 0, 5)
  511. gridLayout.CellSize = UDim2.new(0, 85, 0, 25)
  512. gridLayout.StartCorner = Enum.StartCorner.TopLeft
  513. gridLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  514. gridLayout.SortOrder = Enum.SortOrder.Name -- Sort alphabetically within the category.
  515.  
  516. -- 4. Get, sort, and create the buttons for this category
  517. local sortedLangNames = {}
  518. for langName in pairs(categoryData.Languages) do
  519. table.insert(sortedLangNames, langName)
  520. end
  521. table.sort(sortedLangNames)
  522.  
  523. -- NEW: Store buttons locally for this category
  524. local categoryButtons = {}
  525. for _, langName in ipairs(sortedLangNames) do
  526. local button = Instance.new("TextButton")
  527. button.Name = langName
  528. button.Parent = buttonContainer
  529. button.BackgroundColor3 = Color3.fromRGB(55, 55, 55)
  530. button.BorderColor3 = Color3.fromRGB(80, 80, 80)
  531. button.Font = Enum.Font.SourceSans
  532. button.Text = langName
  533. button.TextColor3 = Color3.fromRGB(255, 255, 255)
  534. button.TextSize = 12
  535. langButtons[langName] = button -- Add to the master list for click logic.
  536. categoryButtons[langName] = button -- NEW: Add to local list for filter logic.
  537. end
  538.  
  539. -- NEW: Add the category's UI elements to the filter table
  540. table.insert(categoryElements, {
  541. header = headerLabel,
  542. container = buttonContainer,
  543. buttons = categoryButtons
  544. })
  545. end
  546.  
  547. --endregion
  548.  
  549. --region UI Logic
  550.  
  551. -- NEW: Function to filter the list based on search text
  552. local function updateFilter(searchText)
  553. local searchTextLower = string.lower(searchText)
  554.  
  555. -- If search is empty, show everything
  556. if searchTextLower == "" then
  557. for _, category in ipairs(categoryElements) do
  558. category.header.Visible = true
  559. category.container.Visible = true
  560. for _, button in pairs(category.buttons) do
  561. button.Visible = true
  562. end
  563. end
  564. return
  565. end
  566.  
  567. -- If search has text, filter
  568. for _, category in ipairs(categoryElements) do
  569. local anyButtonVisible = false
  570.  
  571. -- Check each button in this category
  572. for langName, button in pairs(category.buttons) do
  573. local langNameLower = string.lower(langName)
  574. if string.find(langNameLower, searchTextLower) then
  575. button.Visible = true
  576. anyButtonVisible = true
  577. else
  578. button.Visible = false
  579. end
  580. end
  581.  
  582. -- Show/hide the category header and container
  583. category.header.Visible = anyButtonVisible
  584. category.container.Visible = anyButtonVisible
  585. end
  586. end
  587.  
  588. local isExpanded = false
  589. toggleButton.MouseButton1Click:Connect(function()
  590. isExpanded = not isExpanded
  591. scrollFrame.Visible = isExpanded
  592. if isExpanded then
  593. toggleButton.Text = "[-]"
  594. mainFrame.Size = UDim2.new(0, 280, 0, 300)
  595. -- NEW: Reset the filter when opening
  596. searchBox.Text = ""
  597. updateFilter("")
  598. else
  599. toggleButton.Text = "[+]"
  600. mainFrame.Size = UDim2.new(0, 280, 0, 30)
  601. end
  602. end)
  603.  
  604. local function resetButtonColors()
  605. for _, button in pairs(langButtons) do
  606. button.BackgroundColor3 = Color3.fromRGB(55, 55, 55)
  607. end
  608. stopButton.BackgroundColor3 = Color3.fromRGB(150, 40, 40)
  609. jumbleButton.BackgroundColor3 = Color3.fromRGB(120, 60, 180)
  610. end
  611.  
  612. -- This logic works perfectly with no changes, since we still
  613. -- populated the 'langButtons' and 'languages' tables.
  614. for langName, button in pairs(langButtons) do
  615. button.MouseButton1Click:Connect(function()
  616. resetButtonColors()
  617. button.BackgroundColor3 = Color3.fromRGB(70, 115, 190)
  618. isTranslatorActive = true
  619. isJumbleActive = false -- Deactivate Jumble mode.
  620. targetLanguage = languages[langName]
  621. sys("[TR] Translator enabled. Language set to " .. langName .. ".")
  622. end)
  623. end
  624.  
  625. stopButton.MouseButton1Click:Connect(function()
  626. resetButtonColors()
  627. isTranslatorActive = false
  628. isJumbleActive = false -- Deactivate Jumble mode.
  629. targetLanguage = nil
  630. sys("[TR] Auto-translation DISABLED.")
  631. end)
  632.  
  633. jumbleButton.MouseButton1Click:Connect(function()
  634. resetButtonColors()
  635. jumbleButton.BackgroundColor3 = Color3.fromRGB(160, 90, 220) -- Highlight color.
  636. isTranslatorActive = false
  637. isJumbleActive = true
  638. targetLanguage = nil
  639. sys("[TR] Jumble mode ENABLED. Have fun!")
  640. end)
  641.  
  642. -- NEW: Connect the search box to the filter function
  643. searchBox.Changed:Connect(function()
  644. updateFilter(searchBox.Text)
  645. end)
  646.  
  647. --endregion
  648.  
  649. --region Main Logic
  650. -- This section hooks into the chat system.
  651.  
  652. task.spawn(function()
  653. repeat task.wait() until CoreGui:FindFirstChild("ExperienceChat")
  654. local experienceChat = CoreGui:WaitForChild("ExperienceChat")
  655. local appLayout = experienceChat:WaitForChild("appLayout")
  656. local chatInputBar = appLayout:WaitForChild("chatInputBar")
  657. local background = chatInputBar:WaitForChild("Background")
  658. local container = background:WaitForChild("Container")
  659. local textContainer = container:WaitForChild("TextContainer")
  660. local textBoxContainer = textContainer:WaitForChild("TextBoxContainer")
  661. local textBox = textBoxContainer:WaitForChild("TextBox")
  662. local sendButton = container:WaitForChild("SendButton")
  663.  
  664. local function onSend()
  665. local messageText = textBox.Text
  666. if messageText == "" then return end
  667. textBox.Text = ""
  668. -- The handleOutgoing function will decide if the message needs translation.
  669. if not handleOutgoing(messageText) then
  670. -- If not translated, send the original message.
  671. sendChat(messageText)
  672. end
  673. end
  674.  
  675. textBox.FocusLost:Connect(function(enterPressed)
  676. if enterPressed then onSend() end
  677. end)
  678. sendButton.MouseButton1Click:Connect(onSend)
  679. end)
  680.  
  681. TCS.MessageReceived:Connect(function(msg)
  682. -- Don't translate your own messages or system messages.
  683. if not msg.TextSource or msg.TextSource.UserId == LP.UserId then return end
  684. local userId = msg.TextSource.UserId
  685. local player = Players:GetPlayerByUserId(userId)
  686. local displayName = player and player.DisplayName or tostring(userId)
  687. local userName = player and player.Name or tostring(userId)
  688. local nameString = (displayName == userName) and ("@" .. userName) or (displayName .. " (@" .. userName .. ")")
  689.  
  690. -- Translate the incoming message into English.
  691. local text, detectedLang = translateInfo(msg.Text, yourLanguage, "auto")
  692.  
  693. -- Display the translated message if the translation is different from the original.
  694. if text and text ~= "" and text ~= msg.Text then
  695. local langTag = detectedLang and detectedLang ~= "" and detectedLang:upper() or "AUTO"
  696. sys("(" .. langTag .. ") [" .. nameString .. "]: " .. text)
  697. end
  698. end)
  699.  
  700. sys("[TR] Compact Translator UI loaded.")
  701. sys("[TR] Click the [+] icon on the top-left bar to select a language.")
  702.  
  703. --MEME
Advertisement
Add Comment
Please, Sign In to add comment