SSR and locale
Render translated player UI on the server without a flash of English
Video.js is English by default. Server-rendered pages that opt into another language should mount the relevant provider, output the correct lang, and supply translations on the first client render. Lazy loadLocale and browser translation fallback run after hydration, so controls briefly show English without preloaded copy.
Read Internationalization for provider resolution and merge order.
Set <html lang>
Render the document language on the server:
<html lang="es">
React providers use a server snapshot of undefined for ambient lang, then read <html lang> on hydration. Passing the locale prop explicitly avoids any mismatch.
Preload translations
Import the locale pack on the server (or in a server component) and pass it to I18nProvider:
import { I18nProvider } from '@videojs/react/i18n';
import { Provider, VideoSkin, Video } from '@videojs/react/video';
export async function Player({ locale }: { locale: string }) {
const { default: translations } = await import(`@videojs/react/i18n/locales/${locale}`);
return (
<Provider>
<I18nProvider locale={locale} translations={translations}>
<VideoSkin>
<Video src="..." playsInline />
</VideoSkin>
</I18nProvider>
</Provider>
);
}
translations on the first render skips the async lazy layer and Chrome-only browser translation fallback. Labels match on server and client.
Register on the server
For a shipped pack, import its side-effect module in server bootstrap code before rendering players:
import '@videojs/html/i18n/locales/es/register';
import '@videojs/react/i18n/locales/es/register';
For a custom pack, call registerI18n instead:
import { registerI18n } from '@videojs/html/i18n';
import es from './locales/es';
registerI18n('es', es);
import { registerI18n } from '@videojs/react/i18n';
import es from './locales/es';
registerI18n('es', es);
The registry is module singleton state. Registration in server entry points carries into the client bundle when shared.
next-intl and app routers
import { getLocale } from 'next-intl/server';
const locale = await getLocale();
const { default: translations } = await import(`@videojs/react/i18n/locales/${locale}`);
<I18nProvider locale={locale} translations={translations}>
...
</I18nProvider>
Match your app’s locale negotiation. Video.js does not replace framework i18n; it consumes the tag you pass.
HTML custom elements
SSR HTML players should emit lang and wrap the player with <media-i18n>. Register packs in the entry module loaded before custom elements upgrade:
import '@videojs/html/video';
import '@videojs/html/i18n/locales/es/register';