-
Notifications
You must be signed in to change notification settings - Fork 826
Community voice translation assistant #1866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Community voice translation assistant #1866
Conversation
* fix: lockedKeys in xcstrings * chore: formatting
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Lingo.dev <support@lingo.dev>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add biome formatter * chore: formatting * chore: removed console.log * chore: changeset
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: upd biome formatter * chore: add changeset
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: upd biome formatting logging * chore: add changeset
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: biome JS API v3 bug * chore: add changeset
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Add Product lingodotdev#1 of week badge Added badge for Product Hunt lingodotdev#1 Product of the Week. * Add/update PH badges Updated Product Hunt badge from lingodotdev#1 to lingodotdev#2 for Product of the Day and added couple of other badges * Fix: badge description (week) for Product Hunt recognition * chore: add changeset --------- Co-authored-by: Sumit Saurabh <sumitm4pro@192.168.1.4>
* fix: use initial checksums for all retranslation buckets * chore: add changeset * chore: fix formatting
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add provider settings * chore: formatting and changeset * chore: removed a redundant test
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…otdev#1218) * feat: add 'show locked-keys' and 'show ignored-keys' commands * chore: add changeset * chore: fix formatting
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: regex replacement * chore: add changeset
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
…odotdev#1270) * Add Malayalam translation for README and update i18n.json * chore: add changeset for Malayalam translation update * Update readme/ml.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update readme/ml.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: fix Malayalam README and i18n.json (remove 'or') * chore: add signed commit --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Sumit Saurabh <62152915+sumitsaurabh927@users.noreply.github.com> Co-authored-by: Max Prilutskiy <5614659+maxprilutskiy@users.noreply.github.com> Co-authored-by: Veronica Prilutskaya <veronica@lingo.dev>
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
Co-authored-by: Lingo.dev <support@lingo.dev>
* chore: fix readme * chore: empty changeset
Co-authored-by: Andrei Hirsa <--global>
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
* chore: upgrade to ai sdk 5 to resolve security vulns Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * chore: changeset Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * feat: upgrade to zod 4 Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * chore: remove zod-to-json-schema from the codebase Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: use "Z" not "z" Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: use error.issues Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: perform more zod 4 migrations Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: resolve type errors in mcp.ts (used any, might manually verify everything still works fine) Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: remove defaults from optional fields in zod 4 (fixes failing tests) Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * chore: fmt Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * chore: remove unused zod-to-json-schema dep Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: use prefault Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: revert Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: upgrade new deps Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: sort deps Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * fix: revert to zod 3 for docs script Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * chore: upgrade to ai sdk 6 Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> * chore: sync lockfile Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> --------- Signed-off-by: The-Best-Codes <bestcodes.official@gmail.com> Co-authored-by: Max Prilutskiy <5614659+maxprilutskiy@users.noreply.github.com>
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
* chore: remove old mcp command * chore(cli): changeset
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
…flag is used (lingodotdev#1776) Co-authored-by: AndreyHirsa <--global>
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
…patibility (lingodotdev#1759) * feat(cli): integrate glob package and add lingo.dev command script * feat(cli): add lingo.dev command script for Windows * chore(cli): remove incorrect lingo.dev command script for Windows * chore(cli): rename command script from lingo.dev to lingo * chore(cli): update command handling for Windows 11 bash compatibility --------- Co-authored-by: Max Prilutskiy <5614659+maxprilutskiy@users.noreply.github.com>
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
* feat(cli): integrate glob package and add lingo.dev command script * feat(cli): add lingo.dev command script for Windows * chore(cli): remove incorrect lingo.dev command script for Windows * chore(cli): rename command script from lingo.dev to lingo * chore(cli): update command handling for Windows 11 bash compatibility * chore(cli): rename CLI binary entry point to 'lingo.dev' * chore: add changeset for rolling back 'lingo.dev' version --------- Co-authored-by: Max Prilutskiy <5614659+maxprilutskiy@users.noreply.github.com> Co-authored-by: Veronica Prilutskaya <veronica@lingo.dev>
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
* chore(cli): rename CLI binary entry point from 'lingo' to 'lingo.dev' * chore: add changeset for rolling back 'lingo.dev' version
Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
|
@17prateek12 looks like something bad happened! |
📝 WalkthroughWalkthroughA complete voice-to-text translation application is introduced with Node.js/Express backend and React/Vite frontend. The backend provides a translation API using the Lingo.dev SDK with retry logic. The frontend offers speech recording, transcription, translation to selected target languages, and audio playback of translations. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Browser as Browser/Frontend
participant Backend as Express Backend
participant LingoAPI as Lingo.dev API
User->>Browser: Click "Start Recording"
activate Browser
Browser->>Browser: Capture audio & transcribe (Web Speech API)
User->>Browser: Click "Translate"
Browser->>Browser: Debounce & prepare request
Browser->>Backend: POST /translate {text, targetLocale}
activate Backend
Backend->>Backend: Attempt translation (Retry 1/3)
Backend->>LingoAPI: Translate text
activate LingoAPI
LingoAPI-->>Backend: Translated text
deactivate LingoAPI
Backend-->>Browser: {translated: "..."}
deactivate Backend
Browser->>Browser: Update UI with translation
Browser->>Browser: Speak translation (Web Speech API)
User->>Browser: Hear audio playback
deactivate Browser
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@community/voice-translation-assistance-backend/index.js`:
- Around line 11-16: Set a sane default for PORT and fail fast on missing
required env vars: if process.env.PORT is undefined, default PORT constant (used
by app.listen) to a known value (e.g., 3000) and validate that
process.env.LINGO_API_KEY exists before instantiating LingoDotDevEngine; if
LINGO_API_KEY is missing log an error with context (including the env var name)
and exit process with non-zero status so the app doesn't start or create the SDK
in a partially configured state. Ensure you update the const PORT declaration
and add a pre-check before the new LingoDotDevEngine(...) call that uses
processLogger or console.error and process.exit(1) on failure.
In `@community/voice-translation-assistance-backend/README.md`:
- Around line 15-43: Update the README.md fenced code blocks to include language
identifiers to satisfy MD040: change the project structure block to ```text, the
installation and run-server blocks to ```bash, and the .env example block to
```dotenv; modify the three code fences around the "Project Structure",
"Installation", "Environment Variables" (the `.env` example), and "Run the
Server" sections accordingly so markdownlint passes and rendering improves.
In `@community/voice-translation-assistance-frontend/src/App.css`:
- Line 20: The box-shadow declaration `box-shadow: 5px 2px 5px 2px;` in App.css
is missing a color value; update that declaration to include an explicit color
(for example a hex, rgba()/hsla() with alpha, or a CSS variable like
var(--shadow-color)) so the shadow renders intentionally (e.g., add a color to
`box-shadow: 5px 2px 5px 2px <color>`), and ensure any theme variable exists if
you reference one.
In
`@community/voice-translation-assistance-frontend/src/speech/useSpeechRecognition.ts`:
- Around line 21-22: The inline comment for recognition.continuous is incorrect:
change or remove the misleading comment next to recognition.continuous = false
in useSpeechRecognition.ts so it accurately describes behavior (recognition will
stop automatically after the first final result when continuous is false, not
"stops only when user stops manually"); update the comment text to reflect that
or delete it entirely to avoid confusion.
In
`@community/voice-translation-assistance-frontend/src/speech/useSpeechSynthesis.ts`:
- Around line 5-6: getVoices() may return an empty array on first call; update
useSpeechSynthesis to load and cache voices asynchronously by adding a useEffect
that calls speechSynthesis.getVoices(), assigns them to state (e.g., voices),
and also registers a 'voiceschanged' event listener to update that state when
voices load; then compute voice via voices.find((v) =>
v.lang.startsWith(locale)) from the cached state (not a direct synchronous
getVoices() call), and clean up the event listener on unmount.
In `@community/voice-translation-assistance-frontend/src/VoiceAssistant.tsx`:
- Around line 23-24: translateTimeout and isTranslating are declared as local
lets in the VoiceAssistant component so they reset every render, breaking
debounce and concurrency guards; replace them with persistent refs by creating
const translateTimeoutRef = useRef<any>(null) and const isTranslatingRef =
useRef<boolean>(false) inside the component, update all reads/writes to use
translateTimeoutRef.current and isTranslatingRef.current, and clear/assign the
timeout and toggle the translating flag via those refs (and clean up the timeout
in useEffect return) to preserve state across renders.
🧹 Nitpick comments (11)
community/voice-translation-assistance-backend/envSample (1)
1-2: Consider adding example values to reduce setup friction.
This makes the sample immediately actionable for new users.♻️ Suggested update
-LINGO_API_KEY= -PORT= +LINGO_API_KEY=your_lingodotdev_api_key_here +PORT=3001community/voice-translation-assistance-frontend/src/speech/useSpeechSynthesis.ts (1)
1-14: Consider adding browser support check.Unlike the
useSpeechRecognitionhook which checks for browser support, this hook will throw ifspeechSynthesisis unavailable (e.g., during SSR or in unsupported browsers).Add a guard check
function speak(text: string, locale: string) { + if (typeof speechSynthesis === "undefined") { + console.warn("SpeechSynthesis not supported"); + return; + } const msg = new SpeechSynthesisUtterance(text);community/voice-translation-assistance-frontend/src/speech/useSpeechRecognition.ts (2)
9-11:SpeechRecognitiondetection runs on every render.The browser API lookup runs on each render. While not a performance issue in practice, moving it outside the component or memoizing would be cleaner.
Move detection outside the hook
+const SpeechRecognition = + typeof window !== "undefined" + ? (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition + : null; + export default function useSpeechRecognition() { const [listening, setListening] = useState(false); const [transcript, setTranscript] = useState(""); const recognitionRef = useRef<any>(null); - const SpeechRecognition = - (window as any).SpeechRecognition || - (window as any).webkitSpeechRecognition;
34-36: Error state not exposed to consumers.The error handler logs to console but doesn't update any state. The calling component has no way to know if recognition failed and cannot display appropriate feedback to users.
Consider exposing error state
export default function useSpeechRecognition() { const [listening, setListening] = useState(false); const [transcript, setTranscript] = useState(""); + const [error, setError] = useState<string | null>(null); ... recognition.onerror = (e: any) => { console.error("SpeechRecognition error:", e); + setError(e.error || "Recognition error"); }; ... - return { startListening, stopListening, listening, transcript }; + return { startListening, stopListening, listening, transcript, error }; }community/voice-translation-assistance-frontend/README.md (3)
14-25: Add language specifiers to fenced code blocks.The project structure code block should have a language specifier for proper rendering. Additionally, the documented structure shows
frontend/but the actual path iscommunity/voice-translation-assistance-frontend/.📝 Suggested fix
## 📂 Project Structure -``` +```text frontend/ src/ VoiceAssistant.tsx speech/ useSpeechRecognition.ts useSpeechSynthesis.ts vite.config.ts package.json README.md</details> --- `31-39`: **Add language specifiers to command code blocks.** Per static analysis, fenced code blocks should specify a language for proper syntax highlighting. <details> <summary>📝 Suggested fix</summary> ```diff ## 📦 Installation -``` +```bash npm install
▶️ Start Development Server-
+bash
npm run dev
49-53: Screenshot filenames contain spaces.Filenames with spaces can cause issues in some environments and markdown renderers. Consider renaming screenshots to use hyphens or underscores.
📝 Suggested naming
- - - + + +community/voice-translation-assistance-frontend/src/App.tsx (1)
4-12: Minor formatting inconsistency.Line 8 has an extra leading space before the
<h1>tag compared to the<VoiceAssistant />element. This is a nitpick but worth noting for consistency.📝 Suggested fix
function App() { - return ( <div className="app"> - <h1>🎙️ Multilingual Voice Assistant</h1> + <h1>🎙️ Multilingual Voice Assistant</h1> <VoiceAssistant /> </div> ) }community/voice-translation-assistance-backend/package.json (1)
6-9: MovenodemontodevDependenciesand add a production start script.
nodemonis a development tool for auto-restarting the server during development. It should not be independenciesas it's not needed in production. Additionally, there's no production-ready start script.Suggested changes
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon index.js" + "start": "node index.js", + "dev": "nodemon index.js" }, ... "dependencies": { "cors": "^2.8.6", "dotenv": "^17.2.3", "express": "^5.2.1", - "lingo.dev": "^0.125.0", - "nodemon": "^3.1.11" - } + "lingo.dev": "^0.125.0" + }, + "devDependencies": { + "nodemon": "^3.1.11" + }Also applies to: 14-20
community/voice-translation-assistance-frontend/src/VoiceAssistant.tsx (2)
37-37: Hardcoded backend URL limits deployment flexibility.The URL
http://localhost:3001/translateis hardcoded. For a community demo this is acceptable, but consider using an environment variable for easier configuration.Suggested approach
- const res = await fetch("http://localhost:3001/translate", { + const res = await fetch(`${import.meta.env.VITE_API_URL || 'http://localhost:3001'}/translate`, {
12-12: Minor: Inconsistent indentation.The English language entry has an extra leading space compared to the other entries.
- { code: "en", name: "English" }, + { code: "en", name: "English" },
| const PORT = process.env.PORT; | ||
|
|
||
| const lingo = new LingoDotDevEngine({ | ||
| apiKey: process.env.LINGO_API_KEY, | ||
| timeout:20000, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add default PORT and validate required environment variables at startup.
If PORT is undefined, app.listen(PORT) behavior is unpredictable. If LINGO_API_KEY is missing, the SDK initialization may succeed but fail on first API call, making debugging harder.
Proposed fix
dotenv.config();
+
+const LINGO_API_KEY = process.env.LINGO_API_KEY;
+if (!LINGO_API_KEY) {
+ console.error("❌ Missing required environment variable: LINGO_API_KEY");
+ process.exit(1);
+}
+
const app = express();
app.use(cors());
app.use(express.json());
-const PORT = process.env.PORT;
+const PORT = process.env.PORT || 3001;
const lingo = new LingoDotDevEngine({
- apiKey: process.env.LINGO_API_KEY,
- timeout:20000,
+ apiKey: LINGO_API_KEY,
+ timeout: 20000,
});🤖 Prompt for AI Agents
In `@community/voice-translation-assistance-backend/index.js` around lines 11 -
16, Set a sane default for PORT and fail fast on missing required env vars: if
process.env.PORT is undefined, default PORT constant (used by app.listen) to a
known value (e.g., 3000) and validate that process.env.LINGO_API_KEY exists
before instantiating LingoDotDevEngine; if LINGO_API_KEY is missing log an error
with context (including the env var name) and exit process with non-zero status
so the app doesn't start or create the SDK in a partially configured state.
Ensure you update the const PORT declaration and add a pre-check before the new
LingoDotDevEngine(...) call that uses processLogger or console.error and
process.exit(1) on failure.
| ## 📂 Project Structure | ||
| ``` | ||
| backend/ | ||
| index.js | ||
| package.json | ||
| .env | ||
| README.md | ||
| ``` | ||
|
|
||
| ## 🔧 Requirements | ||
| - Node.js 18+ | ||
| - Lingo.dev API Key | ||
|
|
||
| ## 📦 Installation | ||
| ``` | ||
| npm install | ||
| ``` | ||
|
|
||
| ## 🔐 Environment Variables | ||
| Create `.env`: | ||
| ``` | ||
| LINGO_API_KEY=your_lingodotdev_api_key_here | ||
| PORT=3001 | ||
| ``` | ||
| Noted: use only 3001 port, otherwise in frontend. | ||
|
|
||
| ## ▶️ Run the Server | ||
| ``` | ||
| npm start |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add language identifiers to fenced code blocks (MD040).
This satisfies markdownlint and improves rendering.
✅ Suggested fix
-## 📂 Project Structure
-```
+## 📂 Project Structure
+```text
backend/
index.js
package.json
.env
README.md@@
-## 📦 Installation
- -npm install -
+## 📦 Installation
+bash +npm install +
@@
-Create .env:
- +Create `.env`: +dotenv
LINGO_API_KEY=your_lingodotdev_api_key_here
PORT=3001
@@
-## ▶️ Run the Server
-```
-npm start
-```
+## ▶️ Run the Server
+```bash
+npm start
+```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
16-16: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
29-29: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
42-42: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In `@community/voice-translation-assistance-backend/README.md` around lines 15 -
43, Update the README.md fenced code blocks to include language identifiers to
satisfy MD040: change the project structure block to ```text, the installation
and run-server blocks to ```bash, and the .env example block to ```dotenv;
modify the three code fences around the "Project Structure", "Installation",
"Environment Variables" (the `.env` example), and "Run the Server" sections
accordingly so markdownlint passes and rendering improves.
| flex-direction: column; | ||
| border-radius: 10px; | ||
| padding: 20px; | ||
| box-shadow: 5px 2px 5px 2px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Box-shadow missing color value.
The box-shadow: 5px 2px 5px 2px; declaration is missing a color. Browsers will default to currentColor (black), but this appears unintentional given the shadow syntax structure.
Suggested fix
- box-shadow: 5px 2px 5px 2px;
+ box-shadow: 5px 2px 5px 2px rgba(0, 0, 0, 0.1);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| box-shadow: 5px 2px 5px 2px; | |
| box-shadow: 5px 2px 5px 2px rgba(0, 0, 0, 0.1); |
🤖 Prompt for AI Agents
In `@community/voice-translation-assistance-frontend/src/App.css` at line 20, The
box-shadow declaration `box-shadow: 5px 2px 5px 2px;` in App.css is missing a
color value; update that declaration to include an explicit color (for example a
hex, rgba()/hsla() with alpha, or a CSS variable like var(--shadow-color)) so
the shadow renders intentionally (e.g., add a color to `box-shadow: 5px 2px 5px
2px <color>`), and ensure any theme variable exists if you reference one.
| recognition.interimResults = false; // final results only | ||
| recognition.continuous = false; // stops only when user stops manually |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misleading comment about continuous behavior.
The comment says "stops only when user stops manually" but continuous = false means recognition stops automatically after the first final result. The comment should be corrected or removed.
Suggested fix
recognition.interimResults = false; // final results only
- recognition.continuous = false; // stops only when user stops manually
+ recognition.continuous = false; // stops after first result📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| recognition.interimResults = false; // final results only | |
| recognition.continuous = false; // stops only when user stops manually | |
| recognition.interimResults = false; // final results only | |
| recognition.continuous = false; // stops after first result |
🤖 Prompt for AI Agents
In
`@community/voice-translation-assistance-frontend/src/speech/useSpeechRecognition.ts`
around lines 21 - 22, The inline comment for recognition.continuous is
incorrect: change or remove the misleading comment next to
recognition.continuous = false in useSpeechRecognition.ts so it accurately
describes behavior (recognition will stop automatically after the first final
result when continuous is false, not "stops only when user stops manually");
update the comment text to reflect that or delete it entirely to avoid
confusion.
| const voices = speechSynthesis.getVoices(); | ||
| const voice = voices.find((v) => v.lang.startsWith(locale)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getVoices() may return empty array on first call.
The Web Speech API loads voices asynchronously. Calling getVoices() synchronously often returns an empty array until the voiceschanged event fires. This can cause voice selection to silently fail.
Suggested fix using useEffect to cache voices
+import { useState, useEffect } from "react";
+
export default function useSpeechSynthesis() {
+ const [voices, setVoices] = useState<SpeechSynthesisVoice[]>([]);
+
+ useEffect(() => {
+ const loadVoices = () => setVoices(speechSynthesis.getVoices());
+ loadVoices();
+ speechSynthesis.addEventListener("voiceschanged", loadVoices);
+ return () => speechSynthesis.removeEventListener("voiceschanged", loadVoices);
+ }, []);
+
function speak(text: string, locale: string) {
const msg = new SpeechSynthesisUtterance(text);
-
- const voices = speechSynthesis.getVoices();
const voice = voices.find((v) => v.lang.startsWith(locale));
-
if (voice) msg.voice = voice;
-
speechSynthesis.speak(msg);
}
return { speak };
}🤖 Prompt for AI Agents
In
`@community/voice-translation-assistance-frontend/src/speech/useSpeechSynthesis.ts`
around lines 5 - 6, getVoices() may return an empty array on first call; update
useSpeechSynthesis to load and cache voices asynchronously by adding a useEffect
that calls speechSynthesis.getVoices(), assigns them to state (e.g., voices),
and also registers a 'voiceschanged' event listener to update that state when
voices load; then compute voice via voices.find((v) =>
v.lang.startsWith(locale)) from the cached state (not a direct synchronous
getVoices() call), and clean up the event listener on unmount.
| let translateTimeout: any = null; | ||
| let isTranslating = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Variables reset on every render, breaking debounce and guard logic.
translateTimeout and isTranslating are declared with let inside the component body. They will be re-initialized to null and false on every render, defeating the purpose of debouncing and preventing concurrent calls.
Use useRef to persist these values across renders.
Proposed fix
+import { useState, useRef } from "react";
-import { useState } from "react";
import useSpeechRecognition from "./speech/useSpeechRecognition";
import useSpeechSynthesis from "./speech/useSpeechSynthesis";
...
export default function VoiceAssistant() {
const [translatedText, setTranslatedText] = useState("");
const [targetLocale, setTargetLocale] = useState("es");
const [loading, setLoading] = useState(false);
const { startListening, listening, transcript, stopListening } = useSpeechRecognition();
const { speak } = useSpeechSynthesis();
- let translateTimeout: any = null;
-let isTranslating = false;
+ const translateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
+ const isTranslatingRef = useRef(false);
async function translate() {
- if (isTranslating) return;
+ if (isTranslatingRef.current) return;
if (!transcript) return;
- clearTimeout(translateTimeout);
+ if (translateTimeoutRef.current) clearTimeout(translateTimeoutRef.current);
- translateTimeout = setTimeout(async () => {
- isTranslating = true;
+ translateTimeoutRef.current = setTimeout(async () => {
+ isTranslatingRef.current = true;
setLoading(true);
// ... rest of the function
setLoading(false);
- isTranslating = false;
+ isTranslatingRef.current = false;
}, 300);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let translateTimeout: any = null; | |
| let isTranslating = false; | |
| const translateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); | |
| const isTranslatingRef = useRef(false); |
🤖 Prompt for AI Agents
In `@community/voice-translation-assistance-frontend/src/VoiceAssistant.tsx`
around lines 23 - 24, translateTimeout and isTranslating are declared as local
lets in the VoiceAssistant component so they reset every render, breaking
debounce and concurrency guards; replace them with persistent refs by creating
const translateTimeoutRef = useRef<any>(null) and const isTranslatingRef =
useRef<boolean>(false) inside the component, update all reads/writes to use
translateTimeoutRef.current and isTranslatingRef.current, and clear/assign the
timeout and toggle the translating flag via those refs (and clean up the timeout
in useEffect return) to preserve state across renders.
I noticed that there were a few merge conflicts after the recent commits to main, so I pulled the latest changes and resolved all conflicts on my branch. Everything should now be clean, up-to-date, and working as expected |
No I mean there are so many commits from other branches also. I got to know about this as this branch referenced my branch also. Then I got to know that there are about 190+ commits over this branch |
Voice Translation Assistant Demo
This PR adds a new community project under
/community/voice-translation-assistance.✅ Features
📁 Project Structure
community/
└── voice-translation-assistance-backend/
└── voice-translation-assistance-frontend/
This project is intended as a community demo showing how to use the Lingo.dev SDK in real-time translation workflows.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.