Today I’ll be starting a new series of posts called “Fixing stupid things that should not have been stupid in the first place”, or FSTTSNHBSITFP… Mmmm, just rolls off the tongue.

Anyway.

Logging in to Slack this morning, I noticed an irritating change.

Almost every message was followed by a “Translate” button. What a waste of screen real-estate!

Translate buttons

At first, I thought it was another AI crap. It’s been absolutely everywhere lately.

Okay, I so very much want to get rid of this. But how?

If you’re on Firefox (which you should), just add a uBlock Origin filter for app.slack.com##[class^="translationsBar"].

If you’re on Chrome or a derivative, use Firefox.

But I use the desktop app because I have multiple workspaces open… I know Slack desktop is built with Electron (yuck). Electron is Chromium (yuck two). It does, however mean that it has full devtools somewhere. Good! F12? No. Ctrl + Alt + I? No. The internet claims Slack has a /slackdevtools command that should display the devtools dialog. It doesn’t…

Wait. Doesn’t Chrome have remote a debugging thing? Bingo! Running slack --remote-debugging-port=9222 got the Slack desktop app running and for a second I saw a log line scrolling by that mentioned the port. From there on you should go to http://localhost:9222 where you’re presented with two choices. One for a page type and another for a service worker. I’m already getting way more excited that I should be! But clicking on the “Slack” process gives me an error.

Hmm…

Ah, CORS. The root of like most issues on the web.

slack --remote-debugging-port=9222 --remote-allow-origin=http://localhost:9222.

Much better. First thought is to look for elements with a classname beginning with translationsBar and simply delete them from the DOM.

1
2
3
4
5
6
7
function removeTranslationsElements() {
    const elements = document.querySelectorAll('[class^="translationsBar"]');
    elements.forEach(el => el.remove());
}

// Run the function every 2 seconds
setInterval(removeTranslationsElements, 2000);

It works! Hella cool! But

  1. It’s way too resource intensive
  2. It’s not that smooth…

What about hiding the elements with CSS?

1
2
3
const style = document.createElement("style");
style.textContent = `[class^="translationsBar"] { display: none !important; }`;
document.head.appendChild(style);

Works even better! The buttons are simply gone, and no need to periodically remove them! But it’s still too manual labor-y. Can I script it somehow? Yes!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash

# Get the WebSocket URL from the DevTools JSON
WS_URL=$(curl -s http://localhost:9222/json | jq -r '.[] | select(.type == "page") | .webSocketDebuggerUrl')

# JS to inject <style> tag
JS='const style = document.createElement("style"); style.textContent = `[class^="translationsBar"] { display: none !important; }`; document.head.appendChild(style);'

# Build JSON payload
PAYLOAD=$(jq -nc --arg expr "$JS" '{id: 1, method: "Runtime.evaluate", params: {expression: $expr}}')

# Inject using websocat
echo "$PAYLOAD" | websocat "$WS_URL"

I feel like a frickin’ hackerman doing websocket stuff here!

Now I need to figure out how to persist the new element through restarts. And I don’t really like the idea of constantly having remote devtools accessible.

Digging through The Internet I am repeatedly told to look for ssb-interop.js in the Slack installation directory. Several Reddit and StackOverflow threads point to this elusive file, claiming to allow preloading code before the application starts, all without having to script around it using remote devtools.

Weirdly enough, eventually it is ChatGPT that tells me the ssb-interop.js is deprecated in Slack Desktop client v4, and seems to now be replaced by preload.bundle.js. Coolio! That is a file I can see!

Wait, see where? Yea, Electron seems to package most of the application code in app.asar file. I was able to pacman -Sy asar the cli, and run asar list /usr/lib/slack/resources/app.asar to see the contents of the archive.

From there I vibe-coded (yuck) a script to patch the preload bundle to also load some CSS that hides the translation elements. The script also repacks the app.asar file and places it in the correct directory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/bin/bash

# 🔧 Config
SLACK_APP_PATH="/usr/lib/slack"
ASAR_ORIGINAL="$SLACK_APP_PATH/resources/app.asar"
ASAR_BACKUP="$SLACK_APP_PATH/resources/app.asar.bak"
ASAR_UNPACKED="/path/to/a/dir/slack-asar-unpacked"
PRELOAD_FILE_RELATIVE="dist/preload.bundle.js"

INJECTION='
try {
  const style = document.createElement("style");
  style.textContent = `[class^="translationsBar"] { display: none !important; }`;
  document.addEventListener("DOMContentLoaded", () => {
    document.head.appendChild(style);
  });
} catch (e) {
  console.error("Custom style injection failed", e);
}
'

# 🚨 Stop on error
set -e

# 🧪 Check requirements
command -v asar >/dev/null 2>&1 || { echo >&2 "asar not found. Install it with: npm install -g asar"; exit 1; }

# 💾 Backup original .asar
if [ ! -f "$ASAR_BACKUP" ]; then
  echo "🔄 Backing up original app.asar..."
  cp "$ASAR_ORIGINAL" "$ASAR_BACKUP"
else
  echo "✅ Backup already exists at $ASAR_BACKUP"
fi

# 📦 Extract app.asar
echo "📂 Extracting app.asar..."
rm -rf "$ASAR_UNPACKED"
asar extract "$ASAR_ORIGINAL" "$ASAR_UNPACKED"

# 🧠 Find preload.bundle.js
PRELOAD_PATH="$ASAR_UNPACKED/$PRELOAD_FILE_RELATIVE"
if [ ! -f "$PRELOAD_PATH" ]; then
  echo "❌ preload.bundle.js not found at $PRELOAD_PATH"
  exit 1
fi

# 💉 Inject CSS if not already injected
if grep -q "translationsBar" "$PRELOAD_PATH"; then
  echo "✅ Injection already present in preload.bundle.js"
else
  echo "💉 Injecting custom style into preload.bundle.js..."
  echo -e "\n$INJECTION" >> "$PRELOAD_PATH"
fi

# 📦 Repack asar
echo "📦 Repacking modified app.asar..."
asar pack "$ASAR_UNPACKED" "$ASAR_ORIGINAL"

# 🧼 Clean up
rm -rf "$ASAR_UNPACKED"

echo "✅ Slack patched successfully! Restart Slack to see the changes."

Btw, the script has way too many emojis. But I am too lazy to manually remove them, and I’ve already closed the ChatGPT page to have it do this for me. Oh, well.

Running this script errors out the first time. I forgot sudo because it needs to write to /usr/lib. Fine. sudo ./patch.sh. I am greeted with ✅ Slack patched successfully! Restart Slack to see the changes. - looking around in the restarted Slack app, I see no “Translate” buttons! Party!

Now, tonight of today, writing this post I realized the translation buttons were introduced by an app. I don’t know whether it was installed by Slack themselves or an admin, but I’ve gotten rid of the button now.

Am content.

https://xkcd.com/356/