feat(web): video player i18n (#28192)

This commit is contained in:
Mees Frensel
2026-05-07 13:39:37 +02:00
committed by GitHub
parent f09769a2f3
commit 13587bf13c
3 changed files with 124 additions and 6 deletions
+32 -1
View File
@@ -1524,6 +1524,38 @@
"marked_all_as_read": "Marked all as read",
"matches": "Matches",
"matching_assets": "Matching Assets",
"media_chrome": {
"auto": "Auto",
"captions": "Captions",
"captions_off": "Off",
"closed_captions": "closed captions",
"decode_error": "Decode error",
"disable_captions": "Disable captions",
"enable_captions": "Enable captions",
"enter_fullscreen_mode": "Enter fullscreen mode",
"exit_fullscreen_mode": "Exit fullscreen mode",
"loop": "Loop",
"media_error_description": "A media error caused playback to be aborted. The media could be corrupt or your browser does not support this format.",
"media_loading": "media loading",
"mute": "Mute",
"network_error": "Network error",
"network_error_description": "A network error caused the media download to fail.",
"not_supported_error": "Source Not Supported",
"playback_rate": "Playback rate",
"playback_rate_current": "current playback rate",
"playback_rate_value": "Playback rate {playbackRate}",
"playback_time": "playback time",
"quality": "Quality",
"second": "second",
"seconds": "seconds",
"time_value_of_total_time": "{currentTime} of {totalTime}",
"time_value_remaining": "{time} remaining",
"unmute": "Unmute",
"unsupported_error_description": "An unsupported error occurred. The server or network failed, or your browser does not support this format.",
"video_not_loaded_unknown_time": "video not loaded, unknown time.",
"video_player": "video player",
"volume": "volume"
},
"media_type": "Media type",
"memories": "Memories",
"memories_all_caught_up": "All caught up",
@@ -1762,7 +1794,6 @@
"play_original_video": "Play original video",
"play_original_video_setting_description": "Prefer playback of original videos rather than transcoded videos. If original asset is not compatible it may not playback correctly.",
"play_transcoded_video": "Play transcoded video",
"playback_speed": "Playback speed",
"please_auth_to_access": "Please authenticate to access",
"port": "Port",
"preferences_settings_subtitle": "Manage the app's preferences",
@@ -4,7 +4,7 @@
import { assetViewerFadeDuration } from '$lib/constants';
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
import { castManager } from '$lib/managers/cast-manager.svelte';
import { autoPlayVideo, loopVideo as loopVideoPreference } from '$lib/stores/preferences.store';
import { autoPlayVideo, lang, loopVideo as loopVideoPreference } from '$lib/stores/preferences.store';
import { getAssetMediaUrl, getAssetPlaybackUrl } from '$lib/utils';
import { AssetMediaSize, type AssetResponseDto } from '@immich/sdk';
import { Icon, LoadingSpinner } from '@immich/ui';
@@ -166,6 +166,7 @@
<!-- dir=ltr based on https://github.com/videojs/video.js/issues/949 -->
<media-controller
dir="ltr"
lang={$lang}
nohotkeys
class="dark h-full max-w-full"
style:aspect-ratio={aspectRatio}
@@ -194,14 +195,14 @@
></video>
{#if extendedControls}
<media-settings-menu hidden anchor="auto" class="w-3xs rounded-xl border border-light-300 shadow-sm">
<media-settings-menu hidden anchor="auto" class="min-w-3xs rounded-xl border border-light-300 shadow-sm">
<Icon slot="checked-indicator" icon={mdiCheck} class="m-2" />
<media-settings-menu-item class="mx-1 rounded-lg p-1 ps-2">
{$t('playback_speed')}
{$t('media_chrome.playback_rate')}
<Icon slot="suffix" icon={mdiChevronRight} class="m-2" />
<media-playback-rate-menu slot="submenu" hidden rates="0.5 1 1.5 2">
<Icon slot="back-icon" icon={mdiChevronLeft} class="m-2" />
<span slot="title">{$t('playback_speed')}</span>
<span slot="title">{$t('media_chrome.playback_rate')}</span>
</media-playback-rate-menu>
</media-settings-menu-item>
</media-settings-menu>
+87 -1
View File
@@ -13,7 +13,7 @@
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
import ServerRestartingModal from '$lib/modals/ServerRestartingModal.svelte';
import { Route } from '$lib/route';
import { locale } from '$lib/stores/preferences.store';
import { lang, locale } from '$lib/stores/preferences.store';
import { sidebarStore } from '$lib/stores/sidebar.svelte';
import { closeWebsocketConnection, openWebsocketConnection, websocketStore } from '$lib/stores/websocket';
import { maintenanceShouldRedirect } from '$lib/utils/maintenance';
@@ -35,6 +35,8 @@
toastManager,
TooltipProvider,
} from '@immich/ui';
import { En } from 'media-chrome/lang/en';
import { addTranslation } from 'media-chrome/utils/i18n';
import { onMount, type Snippet } from 'svelte';
import { t } from 'svelte-i18n';
import { get } from 'svelte/store';
@@ -44,6 +46,38 @@
children?: Snippet;
}
const MediaChromeDefaultKeys = [
'Start airplay',
'Stop airplay',
'Audio',
'Start casting',
'Stop casting',
'Enter picture in picture mode',
'Exit picture in picture mode',
'Seek backward',
'Seek forward',
'audio player',
'seek',
'audio tracks',
'chapter: {chapterName}',
'live',
'start airplay',
'stop airplay',
'start casting',
'stop casting',
'enter picture in picture mode',
'exit picture in picture mode',
'seek to live',
'playing live',
'seek back {seekOffset} seconds',
'seek forward {seekOffset} seconds',
'Encryption Error',
'The media is encrypted and there are no keys to decrypt it.',
] as const satisfies Array<keyof typeof En>;
const MediaChromeDefaults = Object.fromEntries(MediaChromeDefaultKeys.map((key) => [key, key])) as {
[K in (typeof MediaChromeDefaultKeys)[number]]: K;
};
$effect(() => {
setTranslations({
cancel: $t('cancel'),
@@ -73,6 +107,58 @@
save: $t('save'),
supporter: $t('supporter'),
});
addTranslation($lang, {
...MediaChromeDefaults,
Captions: $t('media_chrome.captions'),
'Enable captions': $t('media_chrome.enable_captions'),
'Disable captions': $t('media_chrome.disable_captions'),
'Enter fullscreen mode': $t('media_chrome.enter_fullscreen_mode'),
'Exit fullscreen mode': $t('media_chrome.exit_fullscreen_mode'),
Mute: $t('media_chrome.mute'),
Unmute: $t('media_chrome.unmute'),
Loop: $t('media_chrome.loop'),
Play: $t('play'),
Pause: $t('pause'),
'Playback rate': $t('media_chrome.playback_rate'),
'Playback rate {playbackRate}': $t('media_chrome.playback_rate_value'),
Quality: $t('media_chrome.quality'),
Settings: $t('settings'),
Auto: $t('media_chrome.auto'),
'video player': $t('media_chrome.video_player'),
volume: $t('media_chrome.volume'),
'closed captions': $t('media_chrome.closed_captions'),
'current playback rate': $t('media_chrome.playback_rate_current'),
'playback time': $t('media_chrome.playback_time'),
'media loading': $t('media_chrome.media_loading'),
settings: $t('settings'),
quality: $t('media_chrome.quality'),
play: $t('play'),
pause: $t('pause'),
mute: $t('media_chrome.mute'),
unmute: $t('media_chrome.unmute'),
Off: $t('media_chrome.captions_off'),
'enter fullscreen mode': $t('media_chrome.enter_fullscreen_mode'),
'exit fullscreen mode': $t('media_chrome.exit_fullscreen_mode'),
'Network Error': $t('media_chrome.network_error'),
'Decode Error': $t('media_chrome.decode_error'),
'Source Not Supported': $t('media_chrome.not_supported_error'),
'A network error caused the media download to fail.': $t('media_chrome.network_error_description'),
'A media error caused playback to be aborted. The media could be corrupt or your browser does not support this format.':
$t('media_chrome.media_error_description'),
'An unsupported error occurred. The server or network failed, or your browser does not support this format.': $t(
'media_chrome.unsupported_error_description',
),
hour: $t('hour'),
hours: $t('hours'),
minute: $t('minute'),
minutes: $t('minutes'),
second: $t('media_chrome.second'),
seconds: $t('media_chrome.seconds'),
'{time} remaining': $t('media_chrome.time_value_remaining'),
'{currentTime} of {totalTime}': $t('media_chrome.time_value_of_total_time'),
'video not loaded, unknown time.': $t('media_chrome.video_not_loaded_unknown_time'),
});
});
$effect(() => setLocale($locale));