Skip to content

About

Live two-way speech translation for Google Meet, as a Chrome extension

Resources

Stars

55 stars

Watchers

0 watching

Forks

Latest commit

 

History

19 Commits

Folders and files

Repository files navigation

Meet Interpreter

Live two-way speech translation for Google Meet

Any two of 20 languages, both ways. They speak English and you hear Turkish; you speak Turkish and they hear English, in your own voice. A Chrome extension with no backend: the keys stay in your browser.

Languages20, any two of them; English and Turkish by default
ModesVoice, subtitles only or off, for each direction
DelayAbout 1.2 s after each sentence, measured with the real services; Meet's own delay comes on top
BackendNone
InterfaceEnglish or Turkish

Meet Interpreter's panel in a real Google Meet call (Turkish interface)

Features

  • Twenty languages, any two of them in either direction: English, Turkish, German, French, Spanish, Italian, Portuguese, Dutch, Polish, Russian, Ukrainian, Arabic, Greek, Romanian, Swedish, Indonesian, Hindi, Chinese, Japanese and Korean.
  • Listens to the call through Chrome tab capture and to you through your microphone, transcribes both sides with ElevenLabs Scribe v2 Realtime, translates with Claude (or for free, see below) and speaks the result with ElevenLabs v4 Turbo, which keeps a natural pace and starts as fast as the older Flash v2.5. Each sentence goes to the voice with the one before it (and after it, when known), so the intonation carries on between sentences.
  • Your translated voice goes into the call in place of your microphone. Meet keeps working as usual, and muting in Meet stops everything that would reach the call.
  • A mode for each direction: spoken translation, subtitles only (no speech credits used) or off, switchable mid-call from the popup or the panel on the page.
  • In voice mode you hear only the translation; their own voice is muted. In subtitles-only mode and with translation off you hear them normally.
  • Subtitles like a film's, low in the Meet window above Meet's controls: only the translation, in large type, unless the settings ask for their own words under it. While they are still talking, a dimmed draft of their words so far, translated on your computer by Chrome's own translator (free, whichever translation the call uses), stands where the sentence's translation will come. Each line stays long enough to read, at most two at a time. They move above Meet's own captions when those are on, and never take a click.
  • Your own voice clone, recorded on the settings page. The other person's voice is cloned only after you confirm they agreed, and the clone is deleted when the call ends.
  • A panel with both sides' subtitles, the mode switches, the live delay and a usage counter with an estimated cost. It starts as a small button low on the left of the Meet window, opens with a click and can be dragged anywhere. A mark on the button shows when there is a warning to read.
  • Optional call recording: the Meet tab's picture with both sides' audio, saved as MP4 on this computer only.
  • Echo guard, a speaker mode for calls without headphones, automatic reconnects, and Meet's microphone followed automatically.
  • Leaving the call, or leaving Meet in the same tab, ends the translation by itself, so nothing keeps listening or billing. If it stops because of an error (a used-up quota, for example), the panel stays open and says why.
  • Settings changed mid-call apply at once, the call languages included. A service that stops answering is given up after a few seconds, so one stuck sentence never holds up the ones after it.

Read this first.

  • The translated voice starts about 1.2 s after a sentence ends (measured with the real services, Meet's own delay on top; 1.5 s before version 1.1). Most of it is the wait for silence: the extension watches the sound level itself and closes a sentence after 0.7 s of silence, or sooner when the words so far read as a finished sentence. Speech recognition's own silence detection answered about 0.4 s later, so it is not used. In a long turn, finished sentences are translated while the speaker keeps going. Settings can shorten the wait to 0.5 s (about 1 s in all), at the cost of a long sentence being split now and then.
  • Free translation through Chrome's built-in translator is literal: "saat üç" comes out as "15.00 on Friday". Everyday meeting phrases are put in plain words first, but a free DeepL key or Claude gives natural sentences.
  • Two Meet participants on the same computer garble each other's audio, because Meet's adaptive audio and Chrome's echo cancellation treat them as one room. Test with a second device or a second person.
  • Tested in real Meet calls with two and three participants, and automatically in Chromium against a mock Meet call. Meet's page changes over time, so try a call before an important meeting.
  • Group calls work: in a test call with three English speakers taking turns (the real speech services, a stand-in Meet page) each one was translated in order. Every remote voice comes through one translation voice, and when two people talk at the same time usually only one of them is caught.
  • Cloning someone's voice needs their consent, under ElevenLabs' terms and data protection law.

How it works

Meet tab audio  -> Scribe (their language) -> Claude or free -> ElevenLabs -> your headphones and the subtitle bar
your microphone -> Scribe (your language)  -> Claude or free -> ElevenLabs -> the call, in place of your mic
Part Where it runs What it does
src/content/page-hook.js Meet's page Swaps the microphone track on Meet's RTCRtpSender for the translation track, mirrors Meet's mute
src/content/bridge.js Content script Connects the page with the engine, shows the panel and the subtitle bar
src/content/subtitle-bar.js Content script The subtitles low in the Meet window
src/offscreen/engine.js Offscreen document Tab capture, microphone, speech recognition, translation, speech, voice clone, recording
src/offscreen/stt.js Offscreen document Scribe v2 Realtime client: reconnects, keeps audio while reconnecting, recovers a segment the server never commits
src/shared/turn.js Offscreen document Hears from the sound level when a speaker has finished, so each sentence is closed at once
src/offscreen/drafts.js Offscreen document Their words so far, translated on this computer while they talk, for the subtitle drafts
src/offscreen/free-translator.js Offscreen document Free translation: tries free services from the best down
src/background/service-worker.js Service worker Starts and stops sessions, keeps state for the popup

Free translation

Choose Free as the translation model in the settings and no Anthropic key is needed. The extension tries free services from the best quality down and moves to the next one by itself when a service runs out of quota, hits a rate limit, is slow or fails. The page never shows which one translated.

Order Service Free allowance Needs
1 DeepL API Free 500,000 characters a month Your free DeepL key
2 Mistral (mistral-medium-latest) Free plan with rate limits Your free Mistral key; turn off training on your data in Mistral's privacy settings
3 Groq openai/gpt-oss-120b Daily request and token limits per model Your free Groq key
4 Groq qwen/qwen3.8-27b Its own daily limits The same Groq key
5 Chrome's built-in translator No limit, runs on your computer Chrome 138 or newer on desktop
  • With no keys at all, Chrome's translator does the work. Its language packs download once, after a click: the settings page has a button for it, and the popup's Start button does it too.
  • Chrome's translator takes everyday meeting talk word for word ("Let's touch base on Monday" came out as "Pazartesi günü üsse dokunalım", "Sesim geliyor mu?" as "Is my voice coming?"), so such phrases are put in plainer words of the same language before it translates (src/shared/plain.js, English and Turkish, each rewrite checked through Chrome's translator), and the special terms from the settings come back spelled as written. A free DeepL key still gives much more natural sentences.
  • Keys are optional and belong to each person, because free quotas are per account. A key built into the extension could be copied out of it, and everyone would share one quota.
  • Gemini is left out: on its free tier Google may use what you send to improve its products, and people may read it.
  • Speech recognition and speech still use ElevenLabs, so an ElevenLabs key is always needed.

Requirements

  • Chrome 116 or newer (or another Chromium browser); 138 or newer for free translation without keys
  • Node.js 18 or newer, only to build from source
  • An ElevenLabs API key (voice cloning needs a paid plan), and an Anthropic API key unless you choose free translation
  • Headphones

Install

  1. Download meet-interpreter.zip from the latest release and unzip it.
  2. Open chrome://extensions, turn on Developer mode, choose Load unpacked and pick the unzipped meet-interpreter folder.
  3. The settings page opens by itself. The rest, from the ElevenLabs key to your first call, is in the step-by-step guide with pictures: SETUP.md, in Turkish SETUP.tr.md.

Keep the folder where it is: Chrome runs the extension from it. To update, replace the folder's contents with the new release and press reload on the extension.


Run Locally

Windows

Set up WSL first with this guide: https://x.com/UfukDegen/status/1944066889346429338, then follow the macOS steps inside WSL and load the dist folder from \\wsl$\ in Chrome.

macOS

git clone https://github.com/UfukNode/meet-interpreter.git
cd meet-interpreter
npm install
npm run build
Built dist/

Open chrome://extensions, turn on Developer mode, choose Load unpacked and pick the dist folder. After pulling changes, run npm run build again and press reload on the extension. npm run zip builds and packs dist into meet-interpreter.zip, the file a release carries.


Tests

npm test            # unit tests: audio, sentences, echo guard, ordering, speech recognition protocol, settings
npm run test:e2e    # builds, loads the extension into Chromium and drives a mock Meet call
npm run test:scenarios   # the same mock call through restarts, a reload, failures, settings changes and leaving
npm run test:api    # live check of every API with latency numbers (keys in .env)
npm run test:latency     # end of a sentence to its first translated sound, with the real ElevenLabs
npm run test:free   # live check of DeepL, Mistral and Groq free plans (their keys in .env)
node test/meet/mock-call-demo.mjs   # both directions with the real ElevenLabs, recorded by the extension
node test/meet/group-call.mjs       # a four-person call with the real ElevenLabs and Chrome's translator
  • The end-to-end test needs no keys: besides the connection checks it runs a full translation round trip against a local stand-in for the ElevenLabs and Anthropic APIs (test/e2e/mock-api.mjs, reached through a local proxy). With keys in .env it repeats the round trip against the real APIs.
  • The scenario test needs no keys either. The stand-in fails on purpose (a dropped connection, used-up quotas, an overloaded Claude), and the call is restarted, reloaded, switched between modes, changed in the settings, left and closed.
  • Test speech is made with the macOS say command and ffmpeg, so the audio tests run on macOS.
  • For a real call there is a debug copy, compiled in only by npm run build:debug: with localStorage['meet-tercuman-debug'] = '<port>' set on the Meet page and node test/meet/debug-sink-server.mjs <port> running, the extension copies the exact audio it sends to speech recognition, the transcripts and the recording to 127.0.0.1, and the panel shows a DEBUG badge. The normal build ignores the flag.

Security

  • No backend, no analytics and no remote code: everything ships inside the extension.
  • API keys are kept in chrome.storage.local and sent only to the service they belong to: api.elevenlabs.io, api.anthropic.com, and DeepL, Mistral or Groq when you add their keys.
  • The script inside Meet's page makes no network requests. Audio reaches it through a private MessagePort.
  • Nothing reaches the call while Meet shows you as muted, while translation to them is off, or before the call has started.
  • The other person's voice is cloned only after you tick the consent box, and the clone is deleted after the call unless you change that setting.
  • Recordings stay in the extension's storage on your computer until you save or delete them.
  • The panel's controls answer only your own clicks and keys: a script in Meet's page cannot tick the consent box or switch a mode.
  • The debug copy exists only in a debug build (npm run build:debug), shows a DEBUG badge while it runs, and only ever sends to 127.0.0.1.

Costs

The panel counts what a call uses and estimates the cost from list prices: Scribe v2 Realtime is $0.39 an hour per active direction, Flash v2.5 and v4 Turbo speech is $0.04 per 1,000 characters, and Claude is billed per token (Haiku 5.5 is the cheapest). Subtitles-only mode makes no speech at all, and free translation costs nothing. A direction turned off listens to nothing, and 30 seconds after the call ends the translation stops by itself.


License

MIT

About

Live two-way speech translation for Google Meet, as a Chrome extension

Resources

Stars

55 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages