Subtitle guide Workflow guides

How to add multiple subtitle languages to HTML5 video


TL;DR — Add multiple subtitle languages to HTML5 video by preparing separate WebVTT files with language codes, labels, and track elements.

Related tool

HTML5 Video Subtitle Converter

Open HTML5 converter

HTML5 video uses one track element per subtitle language. This guide shows you how to set up multilingual subtitles correctly for maximum accessibility and user experience.

Quick answer

Create one WebVTT file per language, then add one <track> element for each file. Use proper language codes (srclang) and descriptive labels so users can easily switch between languages.

Use the HTML5 Video Subtitle Converter when source subtitles need to be converted to WebVTT first.

Why multiple subtitle languages matter

Offering subtitles in multiple languages:

  • Expands your audience - Viewers who don’t speak the video’s language can still understand the content
  • Improves accessibility - Users can choose their preferred language
  • Boosts SEO - Search engines can index subtitle content in multiple languages
  • Meets compliance requirements - Many regions require multilingual captions for public content

HTML5 video makes this easy with the <track> element, which browsers support natively without requiring JavaScript libraries.

Example

Here’s a complete example with three subtitle languages:

<video controls width="640" height="360">
  <source src="video.mp4" type="video/mp4" />
  <track kind="subtitles" src="captions.en.vtt" srclang="en" label="English" default />
  <track kind="subtitles" src="captions.es.vtt" srclang="es" label="Español" />
  <track kind="subtitles" src="captions.fr.vtt" srclang="fr" label="Français" />
  <track kind="subtitles" src="captions.de.vtt" srclang="de" label="Deutsch" />
  <track kind="subtitles" src="captions.ja.vtt" srclang="ja" label="日本語" />
</video>

Key points:

  • Each <track> points to a separate VTT file
  • srclang uses ISO 639-1 language codes (en, es, fr, de, ja)
  • label is what users see in the subtitle menu (can be in the native language)
  • Only one track has default (English in this example)
  • The browser automatically creates a language selector in the video controls

Each VTT file should contain subtitles for one language only. Don’t mix languages in a single file.

Step-by-step workflow

1. Prepare one subtitle file per language

Start with your source subtitle files. You might have:

  • Original language subtitles (e.g., English SRT)
  • Translated subtitles from a translation service
  • Community-contributed subtitles in various formats

Organize your files:

/subtitles/
  video-1.en.srt
  video-1.es.srt
  video-1.fr.srt
  video-1.de.srt

2. Convert each file to WebVTT

HTML5 video requires WebVTT format. If your subtitles are in SRT, ASS, or another format, convert them first.

For each language:

  1. Open the HTML5 Video Subtitle Converter
  2. Upload or paste the subtitle file
  3. Convert to WebVTT
  4. Download the .vtt file

Batch conversion tip: If you have many files, convert them all at once and save them with consistent naming.

3. Validate each VTT file

Before adding tracks to your video, validate each VTT file to catch syntax errors.

For each VTT file:

  1. Open the WebVTT Validator
  2. Upload the VTT file
  3. Fix any reported errors
  4. Re-validate until it passes

Common validation errors:

  • Missing WEBVTT header
  • Malformed timestamps
  • Invalid cue settings
  • Character encoding issues (must be UTF-8)

4. Use clear, consistent filenames

Good naming conventions make maintenance easier and prevent mistakes.

Recommended pattern:

video-name.language-code.vtt

Examples:

  • product-demo.en.vtt - English
  • product-demo.es.vtt - Spanish (Español)
  • product-demo.fr.vtt - French (Français)
  • product-demo.de.vtt - German (Deutsch)
  • product-demo.pt-BR.vtt - Brazilian Portuguese
  • product-demo.zh-CN.vtt - Simplified Chinese

Why this matters:

  • Easy to identify which file is which
  • Prevents accidentally using the wrong language
  • Makes automated deployment scripts simpler

5. Add one track element per language

Now add the <track> elements to your HTML5 video.

Basic structure:

<video controls>
  <source src="your-video.mp4" type="video/mp4" />
  <track kind="subtitles" 
         src="path/to/captions.en.vtt" 
         srclang="en" 
         label="English" 
         default />
  <track kind="subtitles" 
         src="path/to/captions.es.vtt" 
         srclang="es" 
         label="Español" />
</video>

Track attributes explained:

  • kind - Use "subtitles" for translations, "captions" for same-language accessibility
  • src - Path to the VTT file (can be relative or absolute URL)
  • srclang - ISO 639-1 language code (en, es, fr, de, ja, etc.)
  • label - Display name in the subtitle menu (can be in the native language)
  • default - Makes this track active by default (use on only one track)

6. Test the language selector

After adding all tracks, test in multiple browsers.

Testing checklist:

  1. Load the page with the video
  2. Click the CC (closed captions) button or subtitle menu
  3. Verify all languages appear in the menu
  4. Select each language and confirm subtitles display correctly
  5. Check that the default language loads automatically
  6. Test on mobile devices (iOS Safari, Android Chrome)

Browser compatibility:

  • Chrome, Firefox, Safari, Edge all support multiple subtitle tracks
  • Mobile browsers support track selection through native controls
  • Older browsers (IE11) have limited support

7. Configure CORS if needed

If your VTT files are hosted on a different domain than your video page, you need CORS headers.

Symptom: Subtitles don’t load, console shows CORS error.

Fix: Add this header to your subtitle file server:

Access-Control-Allow-Origin: *

Or restrict to your domain:

Access-Control-Allow-Origin: https://yourdomain.com

See How to fix CORS errors for VTT subtitles for detailed instructions.

Naming tips

Use language codes consistently across all your videos.

ISO 639-1 language codes (most common)

LanguageCodeLabel Example
EnglishenEnglish
SpanishesEspañol
FrenchfrFrançais
GermandeDeutsch
ItalianitItaliano
PortugueseptPortuguês
Japaneseja日本語
Chinese (Simplified)zh中文
Koreanko한국어
RussianruРусский
Arabicarالعربية
Hindihiहिन्दी

Regional variants

For languages with regional differences, use extended codes:

LanguageCodeLabel Example
US Englishen-USEnglish (US)
UK Englishen-GBEnglish (UK)
Brazilian Portuguesept-BRPortuguês (Brasil)
European Portuguesept-PTPortuguês (Portugal)
Simplified Chinesezh-CN中文(简体)
Traditional Chinesezh-TW中文(繁體)
Latin American Spanishes-419Español (Latinoamérica)
European Spanishes-ESEspañol (España)

Best practice: The srclang value should match the actual language of the captions, not the video filename. The browser uses this for accessibility features and language detection.

Common mistakes

Combining multiple languages in one VTT track

Wrong approach:

WEBVTT

1
00:00:01.000 --> 00:00:03.000
Hello (English) / Hola (Spanish)

2
00:00:03.000 --> 00:00:05.000
Welcome (English) / Bienvenido (Spanish)

Why this fails:

  • Users can’t choose their preferred language
  • Clutters the screen with duplicate text
  • Breaks accessibility features
  • Search engines can’t index languages separately

Correct approach: Use separate tracks so the browser can expose each language cleanly. One VTT file = one language.

Forgetting labels

Without labels:

<track kind="subtitles" src="captions.en.vtt" srclang="en" />
<track kind="subtitles" src="captions.es.vtt" srclang="es" />

Problem: The subtitle menu shows language codes (en, es) instead of readable names. Users might not know what es means.

With labels:

<track kind="subtitles" src="captions.en.vtt" srclang="en" label="English" />
<track kind="subtitles" src="captions.es.vtt" srclang="es" label="Español" />

Result: The menu shows “English” and “Español” - much clearer for users.

Pro tip: Use the native language name in the label (e.g., “Español” not “Spanish”, “Français” not “French”). This helps non-English speakers find their language faster.

Setting every track as default

Wrong:

<track kind="subtitles" src="captions.en.vtt" srclang="en" label="English" default />
<track kind="subtitles" src="captions.es.vtt" srclang="es" label="Español" default />
<track kind="subtitles" src="captions.fr.vtt" srclang="fr" label="Français" default />

Problem: Only one track can be default. Browsers handle this inconsistently - some show the first track, others show the last, some show none.

Correct:

<track kind="subtitles" src="captions.en.vtt" srclang="en" label="English" default />
<track kind="subtitles" src="captions.es.vtt" srclang="es" label="Español" />
<track kind="subtitles" src="captions.fr.vtt" srclang="fr" label="Français" />

Best practice: Mark your primary audience’s language as default, or omit default entirely to let users choose.

Using wrong language codes

Wrong:

<track srclang="spanish" label="Spanish" />
<track srclang="eng" label="English" />

Problem: Browsers expect ISO 639-1 codes (es, en), not full language names or 3-letter codes.

Correct:

<track srclang="es" label="Español" />
<track srclang="en" label="English" />

Not testing on mobile

Desktop browsers often have better subtitle controls than mobile browsers. Always test on:

  • iOS Safari (iPhone/iPad)
  • Android Chrome
  • Mobile Firefox

Mobile-specific issues:

  • Some mobile browsers hide the subtitle menu in fullscreen mode
  • Touch targets for subtitle selection might be too small
  • Native video controls vary by device

Mixing kind=“subtitles” and kind=“captions”

Inconsistent:

<track kind="subtitles" src="captions.en.vtt" srclang="en" label="English" />
<track kind="captions" src="captions.es.vtt" srclang="es" label="Español" />

Problem: Some browsers group these separately in the menu, confusing users.

Consistent:

<track kind="subtitles" src="captions.en.vtt" srclang="en" label="English" />
<track kind="subtitles" src="captions.es.vtt" srclang="es" label="Español" />

When to use each:

  • kind="subtitles" - Translations of dialogue
  • kind="captions" - Same-language text including sound effects and speaker IDs (for accessibility)

For multilingual content, use kind="subtitles" consistently.

Advanced: Programmatic track management

For dynamic subtitle loading or user preference storage, use JavaScript:

const video = document.querySelector('video');

// Add a track programmatically
const track = document.createElement('track');
track.kind = 'subtitles';
track.label = 'Português';
track.srclang = 'pt';
track.src = 'captions.pt.vtt';
video.appendChild(track);

// Listen for track changes
video.textTracks.addEventListener('change', () => {
  const activeTrack = Array.from(video.textTracks)
    .find(track => track.mode === 'showing');
  
  if (activeTrack) {
    console.log('Active language:', activeTrack.language);
    // Save user preference to localStorage
    localStorage.setItem('preferredSubtitleLang', activeTrack.language);
  }
});

// Restore user's preferred language
const preferredLang = localStorage.getItem('preferredSubtitleLang');
if (preferredLang) {
  Array.from(video.textTracks).forEach(track => {
    track.mode = track.language === preferredLang ? 'showing' : 'disabled';
  });
}

Frequently asked questions

How many subtitle languages should I offer?

Start with your primary audience’s languages. Common combinations:

  • Global audience: English, Spanish, French, German, Japanese, Chinese
  • European focus: English, German, French, Italian, Spanish
  • Americas focus: English, Spanish (Latin American), Portuguese (Brazilian)

Add more languages based on your analytics data showing where viewers are located.

Can I use the same VTT file for multiple videos?

Only if the timing and dialogue are identical. Usually each video needs its own subtitle files, even if the language is the same.

Do subtitle files slow down page load?

No. Browsers load subtitle files on-demand when the user selects a language or when the default track is activated. They don’t block the initial page load.

Can I auto-detect the user’s language?

Yes, with JavaScript:

const userLang = navigator.language.split('-')[0]; // e.g., 'en' from 'en-US'
const matchingTrack = Array.from(video.textTracks)
  .find(track => track.language === userLang);

if (matchingTrack) {
  matchingTrack.mode = 'showing';
}

What if I don’t have translations yet?

Start with one language (usually English) and add more as you get translations. You can always add new <track> elements later without changing existing ones.

Use the HTML5 Video Subtitle Converter

Convert SRT or ASS subtitles to WebVTT for HTML5 video tracks and browser playback. No signup, no upload, and everything runs locally in the browser.

Open HTML5 converter