Skip to content

Commit 2bcfbb0

Browse files
feat(community): real time video translations (audio and subtitles) (#1914)
* project setup * add web page for a project * add project assets * add types * add websocket server * add translations * add architecture * add documentation * remove translated files from demo * add changeset * create PR * fix code suggetions --------- Co-authored-by: Sumit Saurabh <62152915+sumitsaurabh927@users.noreply.github.com>
1 parent f1a64a6 commit 2bcfbb0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+10777
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
Add Video Translator project to the community directory.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
node_modules
2+
.turbo
3+
4+
# dependencies
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
**/.next/**
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# env files
34+
/.env
35+
apps/next-app/.env
36+
apps/ws-server/.env
37+
38+
# vercel
39+
.vercel
40+
41+
# typescript
42+
*.tsbuildinfo
43+
next-env.d.ts
44+
45+
/public/emotions.mp3

community/video-translator/LICENSE

Lines changed: 397 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
2+
# 🎬 Real-Time Audio + Subtitle Translation Engine for Global Content
3+
4+
## Problem Statement
5+
6+
Global companies rely heavily on video content for marketing, product education, training, and international outreach. However, most video assets are created in a single language typically in English. Translating these videos manually into multiple languages requires: human translators, voiceover artists, subtitle file creation and formatting, repeated engineering work for UI and SEO localization.
7+
8+
The challenge becomes far more complex when translation needs to be real-time, such as: live product demos, training sessions, user education websites, continuous content creation. Traditional translation workflows cannot meet real-time requirements.
9+
This project solves that problem by creating a Real-Time Multilingual Video & Audio Translation System that automatically translates: Speech → Text → Translated Text → Translated Audio → Subtitles in real time
10+
11+
![lingo.video screenshot in hindi](desktop.png)
12+
13+
## Table of Contents
14+
- [lingo.video website](https://lingo-video.vercel.app/)
15+
- [YouTube video](https://youtu.be/AUdZw9KzZzw)
16+
- [Installing](#getting-started)
17+
- [Real-Time Video Subtitles Translation architecture and tech stack](./docs/live-translation-architecture.md)
18+
- [Impact & Benefits for Global Companies](#impact--benefits-for-global-companies)
19+
- [Features](#features)
20+
- [Challenges with Real-Time Translation & How We Solve Them](#challenges-with-real-time-translation--how-we-solve-them)
21+
- [What is next?](./docs/what-is-next.md)
22+
- [Author](#author)
23+
- [License](#license)
24+
25+
## Getting Started
26+
1. Clone repository
27+
```
28+
git clone https://github.com/ShubhamOulkar/lingo.video.git
29+
cd lingo.video
30+
```
31+
2. Install dependencies
32+
```
33+
pnpm install
34+
```
35+
3. Get lingo.dev api key from [`lingo.dev`](https://lingo.dev/)
36+
4. Create `.env` file and store `LINGODOTDEV_API_KEY`
37+
5. Run frontend and websocket server concurrently
38+
```
39+
pnpm dev
40+
```
41+
42+
43+
## Impact & Benefits for Global Companies
44+
This system offers tangible benefits for organizations, especially global food and delivery companies:
45+
46+
- `Eliminates VTT and audio file maintenance`: No need to manually create or store .vtt subtitle files for each language.
47+
48+
- `Reduces database and storage costs`: Subtitles are generated and translated on the fly, so companies don’t pay for storing multiple language files.
49+
50+
- `Minimizes developer workload`: No extra development effort is required to maintain multilingual video content.
51+
52+
- `Reach markets early`: Videos can be shipped in days instead of months, accelerating global reach.
53+
54+
- `Unlimited language support`: AI driven translation opens the door to reaching any country in the world.
55+
56+
- `Focus on product, not translation`: Teams can concentrate on improving the core product while the system handles multilingual content automatically.
57+
58+
## Features
59+
60+
- **Real-Time Subtitle Translation**
61+
- Translates video subtitles on the fly using [`lingo.dev`](https://lingo.dev/en/sdk) SDK and a WebSocket server.
62+
- No need to maintain `.vtt` files for multiple languages.
63+
> Note: This repository includes [.vtt files](./apps/next-app/public/subtitles/emotions.hi.vtt) for manual accuracy testing. You can test it by clicking on `CC` and comparing with live translation.
64+
65+
- **UI Translation in React**
66+
- React UI automatically updates using [`Lingo Compiler`](https://lingo.dev/en/compiler) ⚡🤖.
67+
- Dynamic language compilation without hardcoding translations.
68+
69+
- **SEO-Friendly Multilingual Content**
70+
- Automatically generates meta tags and Open Graph (OG) tags using [`Lingo CLI`](https://lingo.dev/en/cli).
71+
- Fully automatable via CI/CD pipelines.
72+
> note: Verify og cards for hindi [here](https://opengraph.dev/panel?url=https%3A%2F%2Flingo-video.vercel.app%2Fhi)
73+
74+
- **Time and Cost Efficiency**
75+
- Reduces developer effort and eliminates third party translators.
76+
- Ship multilingual content in **days instead of months**.
77+
78+
- **Unlimited Language Support**
79+
- AI driven translation allows reaching any country worldwide.
80+
- Easily add new languages without manual work.
81+
82+
- **Focus on Product, Not Translation**
83+
- Teams can concentrate on improving the core product while translations happen automatically.
84+
85+
- **Scales with Video Volume**
86+
- Can handle large numbers of videos without extra infrastructure or maintenance.
87+
88+
- **Adopt to user prefered system theme**
89+
- Website can adopt automatically to user prefered light or dark theme.
90+
91+
## Challenges with Real Time Translation & How We Solve Them
92+
Real-time translation systems face several technical and operational challenges. This project is designed with production grade solutions to minimize latency, reduce translation costs, and ensure consistent accuracy across high-volume video content.
93+
94+
### ⚠️ Core Challenges
95+
96+
1. **Network Latency** : Real time translation requires fast WebSocket communication. Any network instability can delay subtitle updates.
97+
98+
2. **LLM Token Generation Delay** : Translation quality depends on the speed of token generation from the LLM. High load or large subtitles can increase response time. Lingo SDK do not support streaming.
99+
100+
3. **Redundant Translation Costs** : Many subtitles repeat the same text across videos. Without optimization, the same token generation is billed multiple times.
101+
102+
4. **Cold Start Issues** : Serverless deployments can experience slow startup times, affecting real-time subtitle delivery.
103+
104+
5. **Scaling with High Traffic** : Multiple users watching videos simultaneously can overload translation or socket servers if not optimized.
105+
106+
## Author
107+
- [LinkedIn](www.linkedin.com/in/shubham-oulkar)
108+
- [Frontend Mentor](https://www.frontendmentor.io/profile/ShubhamOulkar)
109+
- [X](https://x.com/shubhuoulkar)
110+
111+
## License
112+
Content submitted by [shubham oulkar](https://github.com/ShubhamOulkar) is Creative Commons Attribution 4.0 International licensed, as found in the [LICENSE](/LICENSE) file.
113+
114+
## 🌐 Readme in other languages
115+
[हिंदी](./docs/readmes/hi.md)[日本語](./docs/readmes/ja.md)[Français](./docs/readmes/fr.md)[Deutsch](./docs/readmes/de.md)[Español](./docs/readmes/es.md)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
.page {
2+
display: flex;
3+
width: 100%;
4+
align-items: center;
5+
justify-content: center;
6+
flex-direction: column;
7+
padding: 1rem;
8+
}
9+
10+
.main {
11+
display: flex;
12+
width: 100%;
13+
flex-direction: column;
14+
align-items: center;
15+
justify-content: center;
16+
gap: 1rem;
17+
18+
> h1 {
19+
margin-block: 3rem;
20+
}
21+
}
22+
23+
.header {
24+
display: flex;
25+
align-items: center;
26+
justify-content: space-around;
27+
gap: 1rem;
28+
padding: 0.5rem 1rem;
29+
width: 100%;
30+
}
31+
32+
.logo {
33+
font-weight: bold;
34+
font-size: 1.5rem;
35+
color: var(--foreground);
36+
border: 2px solid var(--foreground);
37+
border-radius: 6px;
38+
padding: 0.3rem 0.5rem;
39+
}
40+
41+
@media screen and (max-width: 600px) {
42+
.header {
43+
flex-direction: column;
44+
}
45+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import styles from "./page.module.css";
2+
import type { Metadata } from "next";
3+
import VideoPlayer from "@/components/video/Video";
4+
import UiLangPicker from "@/components/uiLangPicker/UiLangPicker";
5+
import ImpactGrid from "@/components/cards/ImpactGrid";
6+
import Footer from "@/components/footer/Footer";
7+
8+
interface Props {
9+
params: Promise<{ lang: string }>;
10+
}
11+
12+
export async function generateStaticParams() {
13+
const locales = ["en", "es", "hi", "ja", "fr", "de"];
14+
return locales.map((lang) => ({ lang }));
15+
}
16+
17+
export async function generateMetadata({ params }: Props): Promise<Metadata> {
18+
const { lang: locale } = await params;
19+
const dictionary = (await import(`../../public/meta-og/${locale}.json`))
20+
.default;
21+
// fetch meta content from your dictionary
22+
const title = dictionary.meta?.title;
23+
const description = dictionary.meta?.description;
24+
// TODO: Generate og images by locale. Now use hindi image as default
25+
return {
26+
title,
27+
description,
28+
twitter: {
29+
title: title,
30+
description: description,
31+
images: "https://lingo-video.vercel.app/desktop.png",
32+
creator: "dev Shubham oulkar",
33+
creatorId: "@shubhuoulkar",
34+
},
35+
openGraph: {
36+
type: "website",
37+
url: `https://lingo-video.vercel.app/${locale}`,
38+
title: title,
39+
description: description,
40+
siteName: "Lingo.video",
41+
images: [{ url: "https://lingo-video.vercel.app/og.png" }],
42+
},
43+
};
44+
}
45+
46+
export default async function Home({ params }: Props) {
47+
const { lang: locale } = await params;
48+
49+
return (
50+
<div className={styles.page}>
51+
<nav className={styles.header}>
52+
<span className={styles.logo}>Lingo.video</span>
53+
<UiLangPicker paramLocale={locale} />
54+
</nav>
55+
<main className={styles.main}>
56+
<h1>Real time video subtitle translations</h1>
57+
<VideoPlayer />
58+
<ImpactGrid />
59+
</main>
60+
<Footer />
61+
</div>
62+
);
63+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
.section {
2+
padding: 3rem 1.5rem;
3+
background-color: var(--background);
4+
text-align: center;
5+
}
6+
7+
.heading {
8+
font-size: 2.25rem;
9+
font-weight: 700;
10+
margin-bottom: 2.5rem;
11+
color: var(--foreground);
12+
}
13+
14+
.grid {
15+
display: grid;
16+
gap: 2rem;
17+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
18+
}
19+
20+
.card {
21+
background: var(--background);
22+
border-radius: 1rem;
23+
padding: 2rem;
24+
box-shadow: 0 5px 15px var(--card-background);
25+
display: flex;
26+
flex-direction: column;
27+
align-items: start;
28+
gap: 1rem;
29+
transition:
30+
transform 0.3s ease,
31+
box-shadow 0.3s ease;
32+
cursor: pointer;
33+
opacity: 0;
34+
transform: translateY(50px);
35+
animation: fadeInUp 0.6s forwards;
36+
37+
> div {
38+
display: flex;
39+
gap: 1rem;
40+
align-items: center;
41+
}
42+
}
43+
44+
.card:nth-child(1) {
45+
animation-delay: 0s;
46+
}
47+
48+
.card:nth-child(2) {
49+
animation-delay: 0.1s;
50+
}
51+
52+
.card:nth-child(3) {
53+
animation-delay: 0.2s;
54+
}
55+
56+
.card:nth-child(4) {
57+
animation-delay: 0.3s;
58+
}
59+
60+
.card:nth-child(5) {
61+
animation-delay: 0.4s;
62+
}
63+
64+
.card:nth-child(6) {
65+
animation-delay: 0.5s;
66+
}
67+
68+
.card:hover {
69+
transform: translateY(-5px);
70+
box-shadow: 0 10px 25px var(--card-background);
71+
}
72+
73+
@keyframes fadeInUp {
74+
to {
75+
opacity: 1;
76+
transform: translateY(0);
77+
}
78+
}
79+
80+
.title {
81+
font-size: 1.25rem;
82+
font-weight: 600;
83+
color: var(--foreground);
84+
text-align: left;
85+
text-wrap: balance;
86+
}
87+
88+
.description {
89+
font-size: 1rem;
90+
color: var(--text-secondary);
91+
}

0 commit comments

Comments
 (0)