Inspiration

I did not start from a dataset. I started from the people sitting around me.

My college takes students from every part of the country, and we arrive speaking different mother tongues into the same lecture hall, where everything is delivered in English. I watched classmates who had cleared the same entrance exam I had — who understood the subject perfectly well — fall behind because of the language it arrived in. They would ask me afterwards what the professor had said. Not what a word meant. What the sentence meant.

That is not a small problem and it is not only mine. Across the world, education is routinely delivered in a language of prestige rather than a language of home — the exchange student in Berlin, the refugee finishing a degree in a country they arrived in last year, the engineering student anywhere whose textbooks are in English and whose thinking is not. Those students fall behind for a reason that has nothing to do with whether they understood the material.

Then I saw the live interpretation used in parliament, where a speech reaches every member in their own language as it is being spoken, and the question became obvious: a room where the decisions are made gets this. Why doesn't a room where people are learning?

The trap that makes the obvious solution harmful

Point an ordinary translator at a lecture and it renders eigenvalue as अभिलक्षणिक मान — correct, literary, and a word that appears in no textbook, no exam, and no job interview.

The student now understands the sentence and cannot answer the question. You have made the lecture easier and the degree harder, and you have quietly built a second-class version of the course for the students who most needed a fair one.

So the design rule came before the code: translate the explanation, never the vocabulary. This is not about discouraging anyone from learning the language of their field — it is the opposite. The terminology is the part that transfers to the exam, the interview, the paper. The improvised sentence that made it make sense is the part that vanishes after four seconds and was never written down anywhere. That sentence is the thing worth rescuing.

What it does

ProfessorTranslate is live interpretation for a classroom.

A professor opens a lecture and speaks normally. Every student joins with a code, picks their own language, and — within about a second — reads and hears the lecture in it. One professor, many languages, in the same room at the same time. No student has to ask for it, and nobody else can tell who is using it.

The technical terms stay in the language of instruction. In the subtitles they are highlighted; in the audio they are spoken by a second voice, in English, inside an otherwise Hindi sentence:

Professor:  "So the eigenvalue of this matrix tells us how much the eigenvector is stretched."

Student:    "तो इस matrix का eigenvalue बताता है कि eigenvector कितना stretch होता है।"
             |__ Hindi voice __|  |English|         |__ Hindi __| |__ English __|

The student understands the sentence and still meets \( \lambda \) called by the name their exam will use.

Around that core:

  • Every student picks their own language, switchable mid-lecture. English, Hindi, Bengali and French today; the system is language-agnostic, so another is a config entry plus a few examples.
  • Diagrams from the lecture itself. When the lecturer describes a plot, Wolfram|Alpha renders it — but it reaches student screens only after the professor approves it. An unreviewed generated diagram on two hundred screens teaches the wrong thing very efficiently.
  • Spoken descriptions of every diagram, translated the same way, so a student who cannot see the board hears what it shows.
  • Lectures archived as text, not audio — so a class replays in a language nobody chose that day, at any speed, or through a screen reader. The same architecture that serves a student who speaks Bengali serves a blind student, without a separate accessibility mode.
  • The glossary builds itself from a PDF of last year's notes or a syllabus URL — and mid-lecture the system listens for subject vocabulary it does not yet protect and offers it to the professor. One tap protects it for the rest of the class.
  • A pre-flight check that tells a professor whether the room's hardware can actually do this, before the students arrive.

Tech stack

TypeScript throughout — React front end, Express + WebSocket server, npm workspaces sharing one set of types across both. Deployed as a single host on Render.

Inference: Featherless AI, running Qwen3-30B-A3B, streamed token by token so the first translated words appear while the sentence is still being generated. Diagrams: Wolfram|Alpha Simple API. Glossary from the web: Firecrawl. Glossary from files: PDF text extraction. Speech in and out: the browser's Web Speech API — deliberately, and this is a social-impact decision as much as a technical one. Recognition and synthesis run on the student's own device, free, with no key and no per-minute cost. A lecturer can walk into a hall and use this without their institution having provisioned or paid for anything. A tool for students who are already at a disadvantage should not have a price tag attached to each minute of listening.

The core mechanism. Before a sentence reaches the model, every protected term is cut out and replaced by a sentinel — ⟦0⟧, ⟦1⟧. The model translates only the connective tissue between the sentinels and carries each sentinel to wherever the target grammar wants it; the real terms are spliced back afterwards. It is not politely asked to preserve vocabulary — it is never given the vocabulary. A prompt can be ignored; an absence cannot. Measured at 0% term loss across 162 translations.

That same pass records where each term landed, which is the only moment the system knows with certainty which characters are term and which are explanation. That boundary drives both the subtitle highlighting and the second voice — which is what makes the rule audible, not merely visible.

Challenges I ran into

Every symptom pointed at the wrong cause. So I stopped guessing and built probes.

"There is a lot of repetition." A live test produced "transverse energy transverse energy transverse energy through and". The cause was event.resultIndex in the Web Speech API. It is documented as where new content begins and universally read as "the first result you have not seen". It is neither: it is the first result that changed, and Chrome keeps pointing at a finalised result while it revises what follows.

"It is skipping lines." Single-sentence tests passed perfectly while real lectures lost words. A sustained-speech probe measured 8.1% of words silently dropped — the segmenter was waiting for punctuation that conversational speech never provides. Now 222 words in, 222 out.

"It is slow." Breaking the delay into five measured stages found the culprit in an unexpected place: the system prompt. Cutting it from 1560 characters to 353 dropped time-to-first-token from 1209 ms to 586 ms.

"The simulations are not live." Diagrams never rendered. The concurrency gate read inFlight >= limit - 1, which with three student languages is permanently true — a one-character bug that no amount of staring at the diagram code would have found.

And the hardest one, which was not a bug at all: the translation was too good. The model's default Hindi was flawless, literary, and harder for a student than the English original. Real classroom speech in India is code-mixed — "अब देखते हैं कि determinant zero हो तो क्या होता है". Making the output sound like a person in a classroom rather than a person in a textbook took a banned list of Sanskritised coinages, a ban on transliteration, worked examples, and a separate masking pass for everyday English loanwords.

What I learned

Fluency is not the same as usefulness. A translation can be perfect by every linguistic measure and still fail the student it was built for. Accessibility work is full of this: the polished version of a tool is often not the one that actually helps.

Constraining the model beat instructing it. Every hour spent making the prompt more emphatic about preserving terminology was worth less than the ten minutes spent making the terminology unreachable.

A test that passes on one sentence tells you nothing about a lecture. Nearly every real bug lived in duration, concurrency, or fragmentation — none of them reachable by a single-shot test.

And accessibility features are rarely single-purpose. I built text archiving so lectures could be replayed in a language chosen later. It turned out to be the feature that lets a screen reader read back a class delivered entirely by voice. The audience I designed for and the audience I helped were not the same audience.

What is real, and what is not

Everything described above runs. Nothing is mocked. Anyone can clone the repo and reproduce these:

Term preservation 0% loss over 162 translations — npm run test:reliability
First translated word on screen ~600 msnpm run test:latency
Words lost from continuous speech 0 — 222 in, 222 out — npm run test:sustained
Automated checks 100+ assertions across 8 suites

But this is a prototype, not a product. It was built in a week and has not yet faced a real class. I would rather say that here than have a judge discover it: a mistranslated sentence costs a student more than no translation would, and a tool aimed at people who are already struggling has to earn trust before it earns users. The next step is one supervised pilot in one real lecture — not more features.

Known limit, stated plainly: a device with no Hindi voice installed produces silence. The app detects this and says so rather than failing quietly — open /check on any device to see. Phones almost always have the voices; Windows laptops often do not.

What's next

Animated demonstrations instead of static plots; generated video for concepts a plot cannot carry; spoken definitions protected like terms; glossaries built from photographs of the board; more languages, and instruction in languages other than English; and cloud speech recognition as an option for noisy halls and strong accents.

Built With

Share this project:

Updates