Dual Subtitles & External Tracks: SRT/VTT/BCC Setup

Watching a foreign course with the original script and a translation on screen together; shipping a video with subtitles baked in so viewers never hunt for files — two small things many web players cannot do, or do awkwardly. ZWPlayer models subtitles as two parallel tracks: primary and secondary, each independently assignable; showing both is dual-subtitle mode. This article walks the developer config, the viewer-side controls, format support, and the usual gotchas.

The Model: Primary + Secondary

ZWPlayer maintains two subtitle slots: track 1 (primary) and track 2 (secondary). Each can hold any subtitle source; both on screen at is dual display — typically original on the primary, translation on the secondary, styled separately.

Dual subtitles Figure 1: English original (primary) and Chinese translation (secondary) shown together

The payoff is compositional freedom: EN+ZH, JA+ZH, original+annotations — same mechanism; mount track and it is a plain single subtitle.

Developer Side: Three Ways to Mount

new ZWPlayer({
  playerElm: 'player',
  url: 'https://example.com/lesson.mp4',
  subtitles: [
    { url: 'https://example.com/en.srt', title: 'English' },
    { url: 'https://example.com/zh.srt', title: '中文' },
  ],
});

The subtitles array mounts in order to tracks 1 and 2 — two entries is a ready-made dual subtitle; is a single. title shows in the subtitle menu.

Way 2: Runtime API per track

player.addSubtitle('https://example.com/zh.srt', '2', '中文');  // url, slot, title

For interactive flows: the viewer picks a language pack, which you mount the secondary track dynamically.

Way 3: Viewers drag their own

Viewers click the subtitle button → “Add subtitle file”, or drop a local SRT straight the player — it lands on the secondary slot without touching your preloaded tracks. Communities that bring their own fansubs use this a lot.

Format Support

Format Notes
SRT The most universal format; every tool reads it
VTT Web standard (WebVTT); HLS native
BCC Bilibili’s JSON subtitle format; common in archives
JSON ZWPlayer’s own structure with richer layout info
Stream tracks HLS/DASH embedded tracks join the same list after preload (see HLS/DASH Subtitle Preload)

Encoding note: save subtitles as UTF-8. GBK-encoded SRT renders as garbage — that is a file problem to fix at the source, not a player compatibility issue.

Viewer Side: The Subtitle Menu

The control-bar subtitle button opens: show/hide, the dual subtitle switch, per-track primary/secondary assignment, add-file, search, and settings.

Subtitle menu Figure 2: the subtitle menu — each track can be assigned to primary or secondary

Embedded stream tracks appear here too, listed by language alongside external ones:

HLS subtitle menu Figure 3: five embedded language tracks from an HLS stream listed with menu actions

Style Tuning

The subtitle settings panel adjusts size, color, outline, background, and position (top/bottom) per track — the classic setup: original smaller on top, translation full-size at the bottom. Every change previews live.

Subtitle style settings Figure 4: the subtitle style panel — size, color, outline, background, position, per track

FAQ

The two lines overlap? Check whether both tracks sit at “bottom” without enough line height — move to “top” or reduce its font size.

Subtitles mounted but not showing? Check in order: the URL is reachable (network panel), the file is UTF-8, and the timeline matches the video duration (orders-of-magnitude mismatch usually means the wrong video cut).

Can a stream track pair with an external for dual display? Yes. Preloaded stream tracks are equal citizens — primary = stream original, secondary = external translation.

Half a second off? The player has built-in subtitle nudging (0.1s steps via shortcuts, whole-track offset with write-back). No need to re-author the file.