Localisation
Every word the built-in chrome shows or reads to a screen reader comes from one strings map with English defaults. Hand the player a partial map in any language: the keys you set replace the English text, the keys you leave out stay English. The key set is the same on Android, iOS, the web, smart TVs, React Native and Flutter, so the one map your app already keeps next to its other translations localises every client.
There is no automatic language detection: the chrome stays English until you pass strings, and it never reads your app’s own resource bundles or string tables. You choose the language the way you choose it for the rest of your UI, then hand the player the matching map.
What the map covers
Section titled “What the map covers”- Every visible word of the chrome — menu rows (subtitles Off, speed Normal, quality Auto), the LIVE chip, the up-next card, the ad chip, pod position, Skip and Learn more, the error overlay’s message and Retry, the casting and AirPlay status, the vertical feed’s sponsored chip, the web ad-blocker notice and the Android download notification.
- Every accessibility label — the same map is what TalkBack, VoiceOver and screen readers on the web announce for each control (see Accessibility below).
Not part of the map:
- Time formats —
m:ss/h:mm:ss, the minus before a live offset and the/between position and duration. - Content-rating pictograms — the age and descriptor icons are artwork, not text.
- Technical error messages —
OGPlayerError.messagestays English; it is meant for your logs. What the viewer reads iserrorGenericor your own error copy. - Your content — titles, track labels from the manifest and subtitle text appear as delivered.
Where to set it, per platform
Section titled “Where to set it, per platform”| Platform | Player chrome | Vertical feed | Track-name language |
|---|---|---|---|
| Android (incl. Android TV) | OGUiConfig.Builder().setStrings(OGStrings) | OGVerticalFeedConfig.Builder().setStrings(…) | — (manifest label) |
| iOS (incl. Apple TV) | OGUIConfig.strings | OGVerticalFeedConfig.strings | — (system) |
| Web | el.config = { strings } | feed.config = { strings } | <og-player lang> or config.locale |
Smart TV (ogplayer/tv) | el.config = { strings } — the web API | — (no feed on TV) | <og-player lang> or config.locale |
| React Native | uiConfig={{ strings }} | config={{ strings }} | — (native players) |
| Flutter | OGUIConfig(strings: OGStrings(…)) | OGVerticalFeedConfig(strings: …) | — (native players) |
Setting the strings
Section titled “Setting the strings”A partial Dutch map on each platform — the full list of keys is in the key table below.
// One flat key → text map — the same keys on every OGPlayer platform.val dutch = OGStrings.fromMap( mapOf( "subtitles" to "Ondertiteling", "subtitlesOff" to "Uit", "playbackSpeed" to "Afspeelsnelheid", "speedNormal" to "Normaal", "quality" to "Videokwaliteit", "qualityAuto" to "Automatisch", "seekForward" to "{seconds} seconden vooruit", "seekBackward" to "{seconds} seconden terug", "goLive" to "Naar live", "errorGeneric" to "Afspeelfout {code}", "retry" to "Opnieuw proberen", ),)// …or typed: OGStrings(subtitles = "Ondertiteling", retry = "Opnieuw proberen")
OGPlayerView( player = player, uiConfig = OGUiConfig.Builder() .setStrings(dutch) .build(),)OGStrings is a Kotlin data class with every key as a property;
OGStrings.fromMap keeps English for missing keys and ignores keys it does
not know.
let dutch = OGStrings(map: [ "subtitles": "Ondertiteling", "subtitlesOff": "Uit", "playbackSpeed": "Afspeelsnelheid", "speedNormal": "Normaal", "quality": "Videokwaliteit", "qualityAuto": "Automatisch", "seekForward": "{seconds} seconden vooruit", "seekBackward": "{seconds} seconden terug", "goLive": "Naar live", "errorGeneric": "Afspeelfout {code}", "retry": "Opnieuw proberen",])// …or field by field: var dutch = OGStrings.english; dutch.retry = "Opnieuw proberen"
var config = OGUIConfig()config.strings = dutchOGPlayerView(player: player, config: config)OGStrings is a struct with every key as a property; .english is the
default, and OGStrings(map:) keeps English for missing keys and ignores keys
it does not know. The chrome renders the strings verbatim — it never looks
them up in your app’s string tables.
<og-player lang="nl"></og-player>
<script type="module"> const el = document.querySelector("og-player"); el.config = { strings: { subtitles: "Ondertiteling", subtitlesOff: "Uit", playbackSpeed: "Afspeelsnelheid", speedNormal: "Normaal", quality: "Videokwaliteit", qualityAuto: "Automatisch", seekForward: "{seconds} seconden vooruit", seekBackward: "{seconds} seconden terug", goLive: "Naar live", errorGeneric: "Afspeelfout {code}", retry: "Opnieuw proberen", }, };</script>strings is a partial map merged over the English defaults, like colors
and dimens; the OGStrings type ships with the package. The lang
attribute (or config.locale) sets the language of
track names — the words themselves always come from
strings. Headless pages set player.strings and player.locale on the
engine.
<script src="./vendor/ogplayer.tv.global.js"></script>
<og-player id="pl" input="remote" lang="nl" style="width:100%;height:100%"></og-player><script> var el = document.getElementById("pl"); el.config = { strings: { subtitles: "Ondertiteling", subtitlesOff: "Uit", playbackSpeed: "Afspeelsnelheid", speedNormal: "Normaal", quality: "Videokwaliteit", qualityAuto: "Automatisch", goLive: "Naar live", skipAd: "Advertentie overslaan", skipIn: "Overslaan over {seconds}", errorGeneric: "Afspeelfout {code}", retry: "Opnieuw proberen", }, }; el.player = new OGPlayerSDK.OGPlayer({ platformProfile: "tv" });</script>Samsung Tizen and LG webOS apps use the web API unchanged: the remote
chrome reads the same strings map — control and screen-reader labels, menu
rows, the skip countdown, the error overlay — and lang (or
config.locale) names language-coded tracks. With a bundler, import
OGPlayer from ogplayer/tv and set config the same way.
import { OGPlayerView, type OGStrings } from 'ogplayer-react-native';
const dutch: Partial<OGStrings> = { subtitles: 'Ondertiteling', subtitlesOff: 'Uit', playbackSpeed: 'Afspeelsnelheid', speedNormal: 'Normaal', quality: 'Videokwaliteit', qualityAuto: 'Automatisch', seekForward: '{seconds} seconden vooruit', seekBackward: '{seconds} seconden terug', goLive: 'Naar live', errorGeneric: 'Afspeelfout {code}', retry: 'Opnieuw proberen',};
<OGPlayerView style={styles.player} source={{ url }} uiConfig={{ strings: dutch }} />Any subset of OGStrings works; missing keys stay English.
const dutch = OGStrings( subtitles: 'Ondertiteling', subtitlesOff: 'Uit', playbackSpeed: 'Afspeelsnelheid', speedNormal: 'Normaal', quality: 'Videokwaliteit', qualityAuto: 'Automatisch', seekForward: '{seconds} seconden vooruit', seekBackward: '{seconds} seconden terug', goLive: 'Naar live', errorGeneric: 'Afspeelfout {code}', retry: 'Opnieuw proberen',);// …or from the map your other clients use: OGStrings.fromMap(map)
OGPlayerView( source: OGMediaItem(url: url), uiConfig: const OGUIConfig(strings: dutch),)Every OGStrings field is optional; an unset one keeps its English default.
Keys a platform does not show are simply unused there — the AirPlay keys on
Android, the cast keys on iOS, the ad-blocker notice outside the web — so one
complete map fits every client unchanged. Keeping the map as JSON beside your
other translations works directly with OGStrings.fromMap (Android, Flutter),
OGStrings(map:) (iOS) and strings (web, React Native).
Placeholders
Section titled “Placeholders”Some strings carry {name} placeholders that the player fills in:
| Placeholder | Filled with | Keys |
|---|---|---|
{seconds} | a number of seconds | seekForward, seekBackward, upNext, skipIn |
{title} | the next item’s title | upNext, playNext |
{n} | a 1-based position | customAction, audioFallback, subtitlesFallback |
{code} | the numeric error code | errorGeneric |
{index}, {count} | position and size of an ad break | adPod |
{count} | the number of running downloads | downloadingItems |
{device} | the receiver’s name | castingTo, airPlayTo |
{speed} | a playback rate such as 1.5 | speedValue |
{height} | a rendition’s height in pixels | qualityHeight |
{kbps} | a rendition’s bitrate | qualityBitrate |
{name}, {channels} | a track name and its channel count | audioChannels |
- Values are inserted verbatim — no escaping, no plural rules, no ICU
syntax. Where a count of one reads differently, the map has its own key
(
downloadingItemsOne). - Put the placeholders wherever your language needs them, or leave one out:
"Volgende over {seconds}"and"{title} begint zo"are both validupNextvalues. - An unknown placeholder is left in the text as written; an inserted value is
never scanned again, so a title that contains
{seconds}stays literal.
Precedence with the existing options
Section titled “Precedence with the existing options”Three options that predate the strings map keep working and win where you set them, so an integration that already localises these keeps its copy:
| Shown text | Wins | Then | Then |
|---|---|---|---|
| Error overlay message | errorMessageProvider (Android, iOS, web) · errorMessages (React Native, Flutter), where it has text for the code | strings.errorGeneric | Playback error {code} |
| Retry button | retryButtonLabel | strings.retry | Retry |
| Up-next card | upNextText | strings.upNext | Next in {seconds} |
A provider that returns nothing for a code falls through to errorGeneric,
so you can write copy for the codes you care about and let the map cover the
rest.
Track names
Section titled “Track names”The subtitle and audio menus list the stream’s own track names. Where a track has no name, each platform names it its own way:
- Web — a track that carries only a language code is named through the
browser’s
Intl.DisplayNames, in the language you set withconfig.localeor the element’slangattribute (<og-player lang="nl">turnsdeinto Duits). The default is English — the page’s or the browser’s language is never assumed — andconfig.localewins over the attribute. Headless pages setplayer.localeon the engine. - iOS — AVFoundation names the tracks in the device language; no option is needed.
- Android — the manifest’s label, else the language code in capitals
(
NL), elsetrackUnknown. - React Native and Flutter —
localeis accepted so one config fits every platform; the Android and iOS players name tracks as described above.
A track that is still nameless reads audioFallback / subtitlesFallback
(Audio 2) on iOS and the web.
Vertical feed
Section titled “Vertical feed”The vertical feed takes the same strings type
through its own config. It reads play, retry, errorGeneric and
sponsored:
OGVerticalFeedView( items = items, config = OGVerticalFeedConfig.Builder() .setStrings(dutch) .build(),)var feedConfig = OGVerticalFeedConfig()feedConfig.strings = dutchOGVerticalFeedView(items: items, config: feedConfig)feed.config = { strings: { sponsored: "Gesponsord", retry: "Opnieuw proberen" },};<OGVerticalFeedView items={items} config={{ strings: dutch }} />OGVerticalFeedView( items: items, config: const OGVerticalFeedConfig(strings: dutch),)On Android, iOS and the web the feed’s errorMessageProvider still wins
over errorGeneric.
Android download notification
Section titled “Android download notification”The offline downloads notification lives
in ogplayer-core, so it takes its three keys through the downloads config.
OGStrings.toDownloadStrings() hands them over from the map you already
built:
OGDownloads.initialize( context, OGDownloadsConfig.Builder() .setNotificationChannelName("Downloads") .setStrings(dutch.toDownloadStrings()) // or OGDownloadStrings(downloading = "Downloaden", …) without the UI module .build(),)A single download shows its own title (downloading when it has none),
several show downloadingItems, and with nothing running the notification
carries the channel name. React Native and Flutter accept the download keys
as part of the map; their download notification keeps the English text.
Accessibility
Section titled “Accessibility”The strings map is also the chrome’s accessibility vocabulary, and every control carries a label on every platform — TalkBack on Android, VoiceOver on iOS and tvOS, ARIA labels on the web and the TV bundle; React Native and Flutter inherit the native players’ labels.
- Play/pause announces the action a press takes — Play, Pause, or Replay once the item has ended.
- Seek buttons announce their step: Seek forward 10 seconds.
- Scrub bar and volume are announced as sliders on every platform
(
seekBar,volume): each reports its current value — the playback position, the volume level — and adjusts with the screen reader’s slider gestures. - The LIVE chip is announced as Go to live (
goLive) — pressing it returns to the live edge. - Mute flips with the state: Mute while the sound is on, Unmute while muted.
- Custom action icons read their own
accessibilityLabel, or Custom action 1, 2, … when you give none.
The demo apps on every platform include a Localised chrome (nl) scenario with a complete Dutch map — see Demo apps.
Key table
Section titled “Key table”Every key, its English default and where it appears. Keys marked with a platform are shown only there; the rest appear wherever the element exists (a TV chrome, for instance, has no fullscreen button).
Transport
Section titled “Transport”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
play | Play | Play button (screen readers); the vertical feed’s play glyph; the play action of Android’s picture-in-picture window | — |
pause | Pause | Pause button (screen readers); the pause action of Android’s picture-in-picture window | — |
replay | Replay | Play button once the item has ended (screen readers) | — |
seekForward | Seek forward {seconds} seconds | Seek-forward button (screen readers) | {seconds} |
seekBackward | Seek back {seconds} seconds | Seek-back button (screen readers) | {seconds} |
next | Next | Playlist next button of the TV remote chrome (screen readers) | — |
previous | Previous | Playlist previous button of the TV remote chrome (screen readers) | — |
volume | Volume | Volume button and volume slider (screen readers) | — |
mute | Mute | Mute action while the sound is on (screen readers) | — |
unmute | Unmute | Unmute action while muted (screen readers) | — |
enterFullscreen | Enter fullscreen | Fullscreen button while embedded (screen readers) | — |
exitFullscreen | Exit fullscreen | Fullscreen button in fullscreen (screen readers) | — |
seekBar | Seek | Scrub bar (screen readers) | — |
customAction | Custom action {n} | A custom action icon without its own accessibility label | {n} |
Tracks, speed and quality
Section titled “Tracks, speed and quality”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
subtitles | Subtitles | Subtitles button (screen readers) | — |
subtitlesOff | Off | The subtitles-menu row that turns subtitles off | — |
audio | Audio | Audio-track button (screen readers) | — |
playbackSpeed | Playback speed | Speed button (screen readers) | — |
speedNormal | Normal | The 1× row of the speed menu | — |
speedValue | {speed}× | Every other row of the speed menu | {speed} |
quality | Video quality | Quality button (screen readers) | — |
qualityAuto | Auto | The adaptive row of the quality menu | — |
qualityHeight | {height}p | A resolution row of the quality menu | {height} |
qualityBitrate | {kbps} kbps | Web: the bitrate beside a quality row | {kbps} |
qualityAdaptive | adaptive | Web: the note beside the adaptive row | — |
audioDefault | Default | Web: the single row of an audio menu without tracks | — |
trackUnknown | Unknown | Android: a track with neither a label nor a language | — |
audioFallback | Audio {n} | iOS, web: an audio track without a name | {n} |
subtitlesFallback | Subtitles {n} | iOS, web: a subtitle track without a name | {n} |
audioChannels | {name} · {channels}ch | An audio row qualified by its channel count | {name}, {channels} |
| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
live | LIVE | The LIVE chip; on Android and iOS also the time readout at the live edge | — |
goLive | Go to live | The LIVE chip (screen readers) — pressing it returns to the live edge | — |
Playlist
Section titled “Playlist”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
upNext | Next in {seconds} | The up-next card | {seconds} |
playNext | Play next: {title} | The up-next card (screen readers) | {title} |
nextVideo | next video | The title in playNext when the next item has none | — |
| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
ad | AD | The ad chip | — |
adPod | {index}/{count} | Position within a multi-ad break | {index}, {count} |
learnMore | Learn more | Android, iOS: the clickthrough button of the SDK’s ad chrome | — |
skipAd | Skip ad | Android, web remote chrome: the skip button once the ad can be skipped | — |
skipIn | Skip in {seconds} | Android, web remote chrome: the skip countdown | {seconds} |
pauseAd | Pause ad | Ad play/pause button while the ad plays (screen readers) | — |
resumeAd | Resume ad | Ad play/pause button while the ad is paused (screen readers) | — |
adBlockedTitle | Ads are blocked | Web: the ad-blocker notice title | — |
adBlockedText | This video is made available with ads, but your ad blocker prevented them from loading. Your video plays on without ads — please consider allowing ads for this site to support it. | Web: the ad-blocker notice, adBlockerPolicy: "notice" | — |
adBlockedTextHard | This video is only available with ads. Please disable your ad blocker for this site, then reload. | Web: the ad-blocker notice, adBlockerPolicy: "block" | — |
adBlockedDismiss | Got it | Web: the notice button, notice policy | — |
adBlockedReload | I disabled it — reload | Web: the notice button, block policy | — |
dismiss | Dismiss | Web: the notice button (screen readers) | — |
Errors
Section titled “Errors”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
errorGeneric | Playback error {code} | The error overlay’s message; the vertical feed’s error state | {code} |
retry | Retry | The Retry button of the error overlay and the vertical feed | — |
Downloads (Android notification)
Section titled “Downloads (Android notification)”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
downloading | Downloading | A single download without a title | — |
downloadingItemsOne | Downloading 1 item | The counted title for one download | — |
downloadingItems | Downloading {count} items | The counted title for several downloads | {count} |
Casting, AirPlay and picture in picture
Section titled “Casting, AirPlay and picture in picture”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
cast | Cast | Android: the cast button (screen readers) | — |
castConnecting | Connecting to cast device | Android: the cast button while connecting | — |
casting | Casting | Android: the cast button while casting; the casting overlay without a device name | — |
castConnectingStatus | Connecting… | Android: the casting overlay while connecting | — |
castingTo | Casting to {device} | Android: the casting overlay | {device} |
airPlay | AirPlay | iOS: the AirPlay overlay without a device name | — |
airPlayTo | AirPlay — {device} | iOS: the AirPlay overlay | {device} |
pipPlaying | Playing in picture in picture | iOS: status text on the player while the video plays in picture in picture | — |
Vertical feed
Section titled “Vertical feed”| Key | English default | Where it appears | Placeholders |
|---|---|---|---|
sponsored | Sponsored | The feed’s default sponsored chip | — |