ts-video-player 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +438 -0
- package/dist/cdn.d.ts +10 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.min.js +1046 -0
- package/dist/cdn.min.js.map +54 -0
- package/dist/cdn.test.d.ts +2 -0
- package/dist/cdn.test.d.ts.map +1 -0
- package/dist/chunk-36x4yhjn.js +765 -0
- package/dist/chunk-36x4yhjn.js.map +12 -0
- package/dist/chunk-eajts2jv.js +4243 -0
- package/dist/chunk-eajts2jv.js.map +42 -0
- package/dist/chunk-z1ehbz9f.js +380 -0
- package/dist/chunk-z1ehbz9f.js.map +19 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/core/audio-gain.d.ts +67 -0
- package/dist/core/audio-gain.d.ts.map +1 -0
- package/dist/core/caption-styles.d.ts +121 -0
- package/dist/core/caption-styles.d.ts.map +1 -0
- package/dist/core/chapters.d.ts +150 -0
- package/dist/core/chapters.d.ts.map +1 -0
- package/dist/core/error-overlay.d.ts +71 -0
- package/dist/core/error-overlay.d.ts.map +1 -0
- package/dist/core/events.d.ts +119 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/features.d.ts +64 -0
- package/dist/core/features.d.ts.map +1 -0
- package/dist/core/i18n.d.ts +132 -0
- package/dist/core/i18n.d.ts.map +1 -0
- package/dist/core/index.d.ts +37 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/live.d.ts +130 -0
- package/dist/core/live.d.ts.map +1 -0
- package/dist/core/media-session.d.ts +38 -0
- package/dist/core/media-session.d.ts.map +1 -0
- package/dist/core/orientation.d.ts +22 -0
- package/dist/core/orientation.d.ts.map +1 -0
- package/dist/core/popover.d.ts +42 -0
- package/dist/core/popover.d.ts.map +1 -0
- package/dist/core/remote-playback.d.ts +195 -0
- package/dist/core/remote-playback.d.ts.map +1 -0
- package/dist/core/settings-menu.d.ts +132 -0
- package/dist/core/settings-menu.d.ts.map +1 -0
- package/dist/core/spinner.d.ts +67 -0
- package/dist/core/spinner.d.ts.map +1 -0
- package/dist/core/state.d.ts +142 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/text-tracks.d.ts +162 -0
- package/dist/core/text-tracks.d.ts.map +1 -0
- package/dist/core/themes.d.ts +213 -0
- package/dist/core/themes.d.ts.map +1 -0
- package/dist/core/thumbnails.d.ts +124 -0
- package/dist/core/thumbnails.d.ts.map +1 -0
- package/dist/core/tooltips.d.ts +100 -0
- package/dist/core/tooltips.d.ts.map +1 -0
- package/dist/elements/base.d.ts +3 -0
- package/dist/elements/base.d.ts.map +1 -0
- package/dist/elements/index.d.ts +33 -0
- package/dist/elements/index.d.ts.map +1 -0
- package/dist/elements/index.js +55 -0
- package/dist/elements/index.js.map +9 -0
- package/dist/elements/media-airplay-button.d.ts +13 -0
- package/dist/elements/media-airplay-button.d.ts.map +1 -0
- package/dist/elements/media-error-display.d.ts +13 -0
- package/dist/elements/media-error-display.d.ts.map +1 -0
- package/dist/elements/media-fullscreen-button.d.ts +13 -0
- package/dist/elements/media-fullscreen-button.d.ts.map +1 -0
- package/dist/elements/media-live-button.d.ts +13 -0
- package/dist/elements/media-live-button.d.ts.map +1 -0
- package/dist/elements/media-mute-button.d.ts +13 -0
- package/dist/elements/media-mute-button.d.ts.map +1 -0
- package/dist/elements/media-pip-button.d.ts +13 -0
- package/dist/elements/media-pip-button.d.ts.map +1 -0
- package/dist/elements/media-play-button.d.ts +14 -0
- package/dist/elements/media-play-button.d.ts.map +1 -0
- package/dist/elements/media-playback-rate-button.d.ts +10 -0
- package/dist/elements/media-playback-rate-button.d.ts.map +1 -0
- package/dist/elements/media-preview-time.d.ts +18 -0
- package/dist/elements/media-preview-time.d.ts.map +1 -0
- package/dist/elements/media-progress-bar.d.ts +16 -0
- package/dist/elements/media-progress-bar.d.ts.map +1 -0
- package/dist/elements/media-remote-playback-button.d.ts +16 -0
- package/dist/elements/media-remote-playback-button.d.ts.map +1 -0
- package/dist/elements/media-seek-button.d.ts +9 -0
- package/dist/elements/media-seek-button.d.ts.map +1 -0
- package/dist/elements/media-settings-menu.d.ts +32 -0
- package/dist/elements/media-settings-menu.d.ts.map +1 -0
- package/dist/elements/media-time-display.d.ts +21 -0
- package/dist/elements/media-time-display.d.ts.map +1 -0
- package/dist/elements/media-time-group.d.ts +22 -0
- package/dist/elements/media-time-group.d.ts.map +1 -0
- package/dist/elements/media-time-separator.d.ts +13 -0
- package/dist/elements/media-time-separator.d.ts.map +1 -0
- package/dist/elements/media-volume-slider.d.ts +16 -0
- package/dist/elements/media-volume-slider.d.ts.map +1 -0
- package/dist/elements/utils.d.ts +27 -0
- package/dist/elements/utils.d.ts.map +1 -0
- package/dist/elements/video-player.d.ts +23 -0
- package/dist/elements/video-player.d.ts.map +1 -0
- package/dist/elements/video-skin.d.ts +23 -0
- package/dist/elements/video-skin.d.ts.map +1 -0
- package/dist/features/captions.d.ts +8 -0
- package/dist/features/captions.d.ts.map +1 -0
- package/dist/features/create-player.d.ts +45 -0
- package/dist/features/create-player.d.ts.map +1 -0
- package/dist/features/fullscreen.d.ts +8 -0
- package/dist/features/fullscreen.d.ts.map +1 -0
- package/dist/features/gestures.d.ts +8 -0
- package/dist/features/gestures.d.ts.map +1 -0
- package/dist/features/index.d.ts +26 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +31 -0
- package/dist/features/index.js.map +9 -0
- package/dist/features/keyboard.d.ts +8 -0
- package/dist/features/keyboard.d.ts.map +1 -0
- package/dist/features/pip.d.ts +8 -0
- package/dist/features/pip.d.ts.map +1 -0
- package/dist/features/playback.d.ts +8 -0
- package/dist/features/playback.d.ts.map +1 -0
- package/dist/features/quality.d.ts +8 -0
- package/dist/features/quality.d.ts.map +1 -0
- package/dist/features/types.d.ts +26 -0
- package/dist/features/types.d.ts.map +1 -0
- package/dist/features/volume.d.ts +8 -0
- package/dist/features/volume.d.ts.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8149 -0
- package/dist/index.js.map +31 -0
- package/dist/layouts/index.d.ts +58 -0
- package/dist/layouts/index.d.ts.map +1 -0
- package/dist/player.d.ts +90 -0
- package/dist/player.d.ts.map +1 -0
- package/dist/plugins/ads.d.ts +311 -0
- package/dist/plugins/ads.d.ts.map +1 -0
- package/dist/plugins/analytics.d.ts +203 -0
- package/dist/plugins/analytics.d.ts.map +1 -0
- package/dist/plugins/end-screen.d.ts +184 -0
- package/dist/plugins/end-screen.d.ts.map +1 -0
- package/dist/plugins/index.d.ts +13 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +20 -0
- package/dist/plugins/index.js.map +9 -0
- package/dist/plugins/skip-segments.d.ts +159 -0
- package/dist/plugins/skip-segments.d.ts.map +1 -0
- package/dist/plugins/watermark.d.ts +157 -0
- package/dist/plugins/watermark.d.ts.map +1 -0
- package/dist/providers/base.d.ts +56 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/dash.d.ts +94 -0
- package/dist/providers/dash.d.ts.map +1 -0
- package/dist/providers/hls.d.ts +182 -0
- package/dist/providers/hls.d.ts.map +1 -0
- package/dist/providers/html5.d.ts +64 -0
- package/dist/providers/html5.d.ts.map +1 -0
- package/dist/providers/index.d.ts +41 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/vimeo.d.ts +157 -0
- package/dist/providers/vimeo.d.ts.map +1 -0
- package/dist/providers/youtube.d.ts +134 -0
- package/dist/providers/youtube.d.ts.map +1 -0
- package/dist/stx/index.d.ts +59 -0
- package/dist/stx/index.d.ts.map +1 -0
- package/dist/stx/index.js +480 -0
- package/dist/stx/index.js.map +11 -0
- package/dist/types.d.ts +724 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui/components.d.ts +121 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +16 -0
- package/dist/ui/index.js.map +9 -0
- package/package.json +109 -0
- package/src/cdn.test.ts +10 -0
- package/src/cdn.ts +60 -0
- package/src/config.ts +25 -0
- package/src/core/audio-gain.ts +171 -0
- package/src/core/caption-styles.ts +568 -0
- package/src/core/chapters.ts +551 -0
- package/src/core/error-overlay.ts +354 -0
- package/src/core/events.ts +552 -0
- package/src/core/features.ts +287 -0
- package/src/core/i18n.ts +590 -0
- package/src/core/index.ts +249 -0
- package/src/core/live.ts +472 -0
- package/src/core/media-session.ts +137 -0
- package/src/core/orientation.ts +57 -0
- package/src/core/popover.ts +143 -0
- package/src/core/remote-playback.ts +661 -0
- package/src/core/settings-menu.ts +630 -0
- package/src/core/spinner.ts +310 -0
- package/src/core/state.ts +476 -0
- package/src/core/text-tracks.ts +599 -0
- package/src/core/themes.ts +607 -0
- package/src/core/thumbnails.ts +457 -0
- package/src/core/tooltips.ts +370 -0
- package/src/elements/base.ts +2 -0
- package/src/elements/index.ts +82 -0
- package/src/elements/media-airplay-button.ts +78 -0
- package/src/elements/media-error-display.ts +47 -0
- package/src/elements/media-fullscreen-button.ts +72 -0
- package/src/elements/media-live-button.ts +65 -0
- package/src/elements/media-mute-button.ts +69 -0
- package/src/elements/media-pip-button.ts +66 -0
- package/src/elements/media-play-button.ts +69 -0
- package/src/elements/media-playback-rate-button.ts +59 -0
- package/src/elements/media-preview-time.ts +75 -0
- package/src/elements/media-progress-bar.ts +200 -0
- package/src/elements/media-remote-playback-button.ts +108 -0
- package/src/elements/media-seek-button.ts +50 -0
- package/src/elements/media-settings-menu.ts +302 -0
- package/src/elements/media-time-display.ts +99 -0
- package/src/elements/media-time-group.ts +41 -0
- package/src/elements/media-time-separator.ts +35 -0
- package/src/elements/media-volume-slider.ts +140 -0
- package/src/elements/utils.ts +82 -0
- package/src/elements/video-player.ts +175 -0
- package/src/elements/video-skin.ts +127 -0
- package/src/features/captions.ts +56 -0
- package/src/features/create-player.ts +91 -0
- package/src/features/fullscreen.ts +44 -0
- package/src/features/gestures.ts +44 -0
- package/src/features/index.ts +44 -0
- package/src/features/keyboard.ts +89 -0
- package/src/features/pip.ts +47 -0
- package/src/features/playback.ts +68 -0
- package/src/features/quality.ts +19 -0
- package/src/features/types.ts +28 -0
- package/src/features/volume.ts +46 -0
- package/src/index.ts +635 -0
- package/src/layouts/index.ts +672 -0
- package/src/player.ts +821 -0
- package/src/plugins/ads.ts +1045 -0
- package/src/plugins/analytics.ts +673 -0
- package/src/plugins/end-screen.ts +793 -0
- package/src/plugins/index.ts +61 -0
- package/src/plugins/skip-segments.ts +537 -0
- package/src/plugins/watermark.ts +537 -0
- package/src/providers/base.ts +197 -0
- package/src/providers/dash.ts +588 -0
- package/src/providers/hls.ts +624 -0
- package/src/providers/html5.ts +473 -0
- package/src/providers/index.ts +97 -0
- package/src/providers/vimeo.ts +533 -0
- package/src/providers/youtube.ts +542 -0
- package/src/stx/index.ts +606 -0
- package/src/types.ts +874 -0
- package/src/ui/components.ts +910 -0
- package/src/ui/index.ts +29 -0
package/src/core/i18n.ts
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internationalization (i18n) System
|
|
3
|
+
*
|
|
4
|
+
* Provides translation support for all player UI strings.
|
|
5
|
+
*
|
|
6
|
+
* @module core/i18n
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Types
|
|
11
|
+
// =============================================================================
|
|
12
|
+
|
|
13
|
+
export interface TranslationStrings {
|
|
14
|
+
// Playback
|
|
15
|
+
play: string
|
|
16
|
+
pause: string
|
|
17
|
+
replay: string
|
|
18
|
+
// Volume
|
|
19
|
+
mute: string
|
|
20
|
+
unmute: string
|
|
21
|
+
volume: string
|
|
22
|
+
// Progress
|
|
23
|
+
seekBackward: string
|
|
24
|
+
seekForward: string
|
|
25
|
+
seekTo: string
|
|
26
|
+
duration: string
|
|
27
|
+
currentTime: string
|
|
28
|
+
played: string
|
|
29
|
+
buffered: string
|
|
30
|
+
// Fullscreen
|
|
31
|
+
enterFullscreen: string
|
|
32
|
+
exitFullscreen: string
|
|
33
|
+
// PiP
|
|
34
|
+
enterPiP: string
|
|
35
|
+
exitPiP: string
|
|
36
|
+
// Captions
|
|
37
|
+
enableCaptions: string
|
|
38
|
+
disableCaptions: string
|
|
39
|
+
captions: string
|
|
40
|
+
captionsOff: string
|
|
41
|
+
// Settings
|
|
42
|
+
settings: string
|
|
43
|
+
quality: string
|
|
44
|
+
auto: string
|
|
45
|
+
speed: string
|
|
46
|
+
normal: string
|
|
47
|
+
loop: string
|
|
48
|
+
loopEnabled: string
|
|
49
|
+
loopDisabled: string
|
|
50
|
+
// Audio
|
|
51
|
+
audioBoost: string
|
|
52
|
+
audioTrack: string
|
|
53
|
+
// Live
|
|
54
|
+
live: string
|
|
55
|
+
liveEdge: string
|
|
56
|
+
seekToLive: string
|
|
57
|
+
behindLive: string
|
|
58
|
+
// Errors
|
|
59
|
+
networkError: string
|
|
60
|
+
mediaError: string
|
|
61
|
+
unknownError: string
|
|
62
|
+
// Loading
|
|
63
|
+
loading: string
|
|
64
|
+
buffering: string
|
|
65
|
+
// Chapters
|
|
66
|
+
chapters: string
|
|
67
|
+
// AirPlay / Cast
|
|
68
|
+
airPlay: string
|
|
69
|
+
googleCast: string
|
|
70
|
+
casting: string
|
|
71
|
+
// Misc
|
|
72
|
+
download: string
|
|
73
|
+
share: string
|
|
74
|
+
close: string
|
|
75
|
+
menu: string
|
|
76
|
+
back: string
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type TranslationKey = keyof TranslationStrings
|
|
80
|
+
|
|
81
|
+
export interface I18nConfig {
|
|
82
|
+
/** Current language code */
|
|
83
|
+
language?: string
|
|
84
|
+
/** Fallback language code */
|
|
85
|
+
fallbackLanguage?: string
|
|
86
|
+
/** Custom translations */
|
|
87
|
+
translations?: Partial<Record<string, Partial<TranslationStrings>>>
|
|
88
|
+
/** Interpolation pattern (default: {key}) */
|
|
89
|
+
interpolationPattern?: RegExp
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// Default Translations
|
|
94
|
+
// =============================================================================
|
|
95
|
+
|
|
96
|
+
export const englishStrings: TranslationStrings = {
|
|
97
|
+
// Playback
|
|
98
|
+
play: 'Play',
|
|
99
|
+
pause: 'Pause',
|
|
100
|
+
replay: 'Replay',
|
|
101
|
+
// Volume
|
|
102
|
+
mute: 'Mute',
|
|
103
|
+
unmute: 'Unmute',
|
|
104
|
+
volume: 'Volume',
|
|
105
|
+
// Progress
|
|
106
|
+
seekBackward: 'Seek backward {seconds} seconds',
|
|
107
|
+
seekForward: 'Seek forward {seconds} seconds',
|
|
108
|
+
seekTo: 'Seek to {time}',
|
|
109
|
+
duration: 'Duration',
|
|
110
|
+
currentTime: 'Current time',
|
|
111
|
+
played: 'Played',
|
|
112
|
+
buffered: 'Buffered',
|
|
113
|
+
// Fullscreen
|
|
114
|
+
enterFullscreen: 'Enter fullscreen',
|
|
115
|
+
exitFullscreen: 'Exit fullscreen',
|
|
116
|
+
// PiP
|
|
117
|
+
enterPiP: 'Enter picture-in-picture',
|
|
118
|
+
exitPiP: 'Exit picture-in-picture',
|
|
119
|
+
// Captions
|
|
120
|
+
enableCaptions: 'Enable captions',
|
|
121
|
+
disableCaptions: 'Disable captions',
|
|
122
|
+
captions: 'Captions',
|
|
123
|
+
captionsOff: 'Off',
|
|
124
|
+
// Settings
|
|
125
|
+
settings: 'Settings',
|
|
126
|
+
quality: 'Quality',
|
|
127
|
+
auto: 'Auto',
|
|
128
|
+
speed: 'Speed',
|
|
129
|
+
normal: 'Normal',
|
|
130
|
+
loop: 'Loop',
|
|
131
|
+
loopEnabled: 'Loop enabled',
|
|
132
|
+
loopDisabled: 'Loop disabled',
|
|
133
|
+
// Audio
|
|
134
|
+
audioBoost: 'Audio boost',
|
|
135
|
+
audioTrack: 'Audio track',
|
|
136
|
+
// Live
|
|
137
|
+
live: 'LIVE',
|
|
138
|
+
liveEdge: 'At live edge',
|
|
139
|
+
seekToLive: 'Seek to live edge',
|
|
140
|
+
behindLive: '{seconds}s behind',
|
|
141
|
+
// Errors
|
|
142
|
+
networkError: 'A network error occurred',
|
|
143
|
+
mediaError: 'The media could not be loaded',
|
|
144
|
+
unknownError: 'An unknown error occurred',
|
|
145
|
+
// Loading
|
|
146
|
+
loading: 'Loading',
|
|
147
|
+
buffering: 'Buffering',
|
|
148
|
+
// Chapters
|
|
149
|
+
chapters: 'Chapters',
|
|
150
|
+
// AirPlay / Cast
|
|
151
|
+
airPlay: 'AirPlay',
|
|
152
|
+
googleCast: 'Cast',
|
|
153
|
+
casting: 'Casting to {device}',
|
|
154
|
+
// Misc
|
|
155
|
+
download: 'Download',
|
|
156
|
+
share: 'Share',
|
|
157
|
+
close: 'Close',
|
|
158
|
+
menu: 'Menu',
|
|
159
|
+
back: 'Back',
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const spanishStrings: TranslationStrings = {
|
|
163
|
+
play: 'Reproducir',
|
|
164
|
+
pause: 'Pausar',
|
|
165
|
+
replay: 'Repetir',
|
|
166
|
+
mute: 'Silenciar',
|
|
167
|
+
unmute: 'Activar sonido',
|
|
168
|
+
volume: 'Volumen',
|
|
169
|
+
seekBackward: 'Retroceder {seconds} segundos',
|
|
170
|
+
seekForward: 'Avanzar {seconds} segundos',
|
|
171
|
+
seekTo: 'Ir a {time}',
|
|
172
|
+
duration: 'Duración',
|
|
173
|
+
currentTime: 'Tiempo actual',
|
|
174
|
+
played: 'Reproducido',
|
|
175
|
+
buffered: 'Almacenado',
|
|
176
|
+
enterFullscreen: 'Pantalla completa',
|
|
177
|
+
exitFullscreen: 'Salir de pantalla completa',
|
|
178
|
+
enterPiP: 'Imagen en imagen',
|
|
179
|
+
exitPiP: 'Salir de imagen en imagen',
|
|
180
|
+
enableCaptions: 'Activar subtítulos',
|
|
181
|
+
disableCaptions: 'Desactivar subtítulos',
|
|
182
|
+
captions: 'Subtítulos',
|
|
183
|
+
captionsOff: 'Desactivados',
|
|
184
|
+
settings: 'Ajustes',
|
|
185
|
+
quality: 'Calidad',
|
|
186
|
+
auto: 'Automático',
|
|
187
|
+
speed: 'Velocidad',
|
|
188
|
+
normal: 'Normal',
|
|
189
|
+
loop: 'Bucle',
|
|
190
|
+
loopEnabled: 'Bucle activado',
|
|
191
|
+
loopDisabled: 'Bucle desactivado',
|
|
192
|
+
audioBoost: 'Aumento de audio',
|
|
193
|
+
audioTrack: 'Pista de audio',
|
|
194
|
+
live: 'EN VIVO',
|
|
195
|
+
liveEdge: 'En vivo',
|
|
196
|
+
seekToLive: 'Ir al directo',
|
|
197
|
+
behindLive: '{seconds}s de retraso',
|
|
198
|
+
networkError: 'Error de red',
|
|
199
|
+
mediaError: 'No se pudo cargar el medio',
|
|
200
|
+
unknownError: 'Error desconocido',
|
|
201
|
+
loading: 'Cargando',
|
|
202
|
+
buffering: 'Almacenando',
|
|
203
|
+
chapters: 'Capítulos',
|
|
204
|
+
airPlay: 'AirPlay',
|
|
205
|
+
googleCast: 'Enviar',
|
|
206
|
+
casting: 'Enviando a {device}',
|
|
207
|
+
download: 'Descargar',
|
|
208
|
+
share: 'Compartir',
|
|
209
|
+
close: 'Cerrar',
|
|
210
|
+
menu: 'Menú',
|
|
211
|
+
back: 'Volver',
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export const frenchStrings: TranslationStrings = {
|
|
215
|
+
play: 'Lecture',
|
|
216
|
+
pause: 'Pause',
|
|
217
|
+
replay: 'Relire',
|
|
218
|
+
mute: 'Muet',
|
|
219
|
+
unmute: 'Son activé',
|
|
220
|
+
volume: 'Volume',
|
|
221
|
+
seekBackward: 'Reculer de {seconds} secondes',
|
|
222
|
+
seekForward: 'Avancer de {seconds} secondes',
|
|
223
|
+
seekTo: 'Aller à {time}',
|
|
224
|
+
duration: 'Durée',
|
|
225
|
+
currentTime: 'Temps actuel',
|
|
226
|
+
played: 'Joué',
|
|
227
|
+
buffered: 'Mis en mémoire tampon',
|
|
228
|
+
enterFullscreen: 'Plein écran',
|
|
229
|
+
exitFullscreen: 'Quitter le plein écran',
|
|
230
|
+
enterPiP: 'Image dans l\'image',
|
|
231
|
+
exitPiP: 'Quitter l\'image dans l\'image',
|
|
232
|
+
enableCaptions: 'Activer les sous-titres',
|
|
233
|
+
disableCaptions: 'Désactiver les sous-titres',
|
|
234
|
+
captions: 'Sous-titres',
|
|
235
|
+
captionsOff: 'Désactivés',
|
|
236
|
+
settings: 'Paramètres',
|
|
237
|
+
quality: 'Qualité',
|
|
238
|
+
auto: 'Auto',
|
|
239
|
+
speed: 'Vitesse',
|
|
240
|
+
normal: 'Normal',
|
|
241
|
+
loop: 'Boucle',
|
|
242
|
+
loopEnabled: 'Boucle activée',
|
|
243
|
+
loopDisabled: 'Boucle désactivée',
|
|
244
|
+
audioBoost: 'Amplification audio',
|
|
245
|
+
audioTrack: 'Piste audio',
|
|
246
|
+
live: 'EN DIRECT',
|
|
247
|
+
liveEdge: 'En direct',
|
|
248
|
+
seekToLive: 'Aller au direct',
|
|
249
|
+
behindLive: '{seconds}s de retard',
|
|
250
|
+
networkError: 'Erreur réseau',
|
|
251
|
+
mediaError: 'Le média n\'a pas pu être chargé',
|
|
252
|
+
unknownError: 'Erreur inconnue',
|
|
253
|
+
loading: 'Chargement',
|
|
254
|
+
buffering: 'Mise en mémoire tampon',
|
|
255
|
+
chapters: 'Chapitres',
|
|
256
|
+
airPlay: 'AirPlay',
|
|
257
|
+
googleCast: 'Caster',
|
|
258
|
+
casting: 'Diffusion sur {device}',
|
|
259
|
+
download: 'Télécharger',
|
|
260
|
+
share: 'Partager',
|
|
261
|
+
close: 'Fermer',
|
|
262
|
+
menu: 'Menu',
|
|
263
|
+
back: 'Retour',
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export const germanStrings: TranslationStrings = {
|
|
267
|
+
play: 'Abspielen',
|
|
268
|
+
pause: 'Pause',
|
|
269
|
+
replay: 'Wiederholen',
|
|
270
|
+
mute: 'Stumm',
|
|
271
|
+
unmute: 'Ton an',
|
|
272
|
+
volume: 'Lautstärke',
|
|
273
|
+
seekBackward: '{seconds} Sekunden zurück',
|
|
274
|
+
seekForward: '{seconds} Sekunden vor',
|
|
275
|
+
seekTo: 'Zu {time} springen',
|
|
276
|
+
duration: 'Dauer',
|
|
277
|
+
currentTime: 'Aktuelle Zeit',
|
|
278
|
+
played: 'Abgespielt',
|
|
279
|
+
buffered: 'Gepuffert',
|
|
280
|
+
enterFullscreen: 'Vollbild',
|
|
281
|
+
exitFullscreen: 'Vollbild beenden',
|
|
282
|
+
enterPiP: 'Bild-in-Bild',
|
|
283
|
+
exitPiP: 'Bild-in-Bild beenden',
|
|
284
|
+
enableCaptions: 'Untertitel aktivieren',
|
|
285
|
+
disableCaptions: 'Untertitel deaktivieren',
|
|
286
|
+
captions: 'Untertitel',
|
|
287
|
+
captionsOff: 'Aus',
|
|
288
|
+
settings: 'Einstellungen',
|
|
289
|
+
quality: 'Qualität',
|
|
290
|
+
auto: 'Auto',
|
|
291
|
+
speed: 'Geschwindigkeit',
|
|
292
|
+
normal: 'Normal',
|
|
293
|
+
loop: 'Schleife',
|
|
294
|
+
loopEnabled: 'Schleife aktiviert',
|
|
295
|
+
loopDisabled: 'Schleife deaktiviert',
|
|
296
|
+
audioBoost: 'Audio-Verstärkung',
|
|
297
|
+
audioTrack: 'Audiospur',
|
|
298
|
+
live: 'LIVE',
|
|
299
|
+
liveEdge: 'Am Live-Punkt',
|
|
300
|
+
seekToLive: 'Zum Live-Punkt',
|
|
301
|
+
behindLive: '{seconds}s hinter Live',
|
|
302
|
+
networkError: 'Netzwerkfehler',
|
|
303
|
+
mediaError: 'Medium konnte nicht geladen werden',
|
|
304
|
+
unknownError: 'Unbekannter Fehler',
|
|
305
|
+
loading: 'Wird geladen',
|
|
306
|
+
buffering: 'Puffern',
|
|
307
|
+
chapters: 'Kapitel',
|
|
308
|
+
airPlay: 'AirPlay',
|
|
309
|
+
googleCast: 'Streamen',
|
|
310
|
+
casting: 'Streame zu {device}',
|
|
311
|
+
download: 'Herunterladen',
|
|
312
|
+
share: 'Teilen',
|
|
313
|
+
close: 'Schließen',
|
|
314
|
+
menu: 'Menü',
|
|
315
|
+
back: 'Zurück',
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export const japaneseStrings: TranslationStrings = {
|
|
319
|
+
play: '再生',
|
|
320
|
+
pause: '一時停止',
|
|
321
|
+
replay: 'リプレイ',
|
|
322
|
+
mute: 'ミュート',
|
|
323
|
+
unmute: 'ミュート解除',
|
|
324
|
+
volume: '音量',
|
|
325
|
+
seekBackward: '{seconds}秒戻る',
|
|
326
|
+
seekForward: '{seconds}秒進む',
|
|
327
|
+
seekTo: '{time}にシーク',
|
|
328
|
+
duration: '長さ',
|
|
329
|
+
currentTime: '現在の時間',
|
|
330
|
+
played: '再生済み',
|
|
331
|
+
buffered: 'バッファ済み',
|
|
332
|
+
enterFullscreen: 'フルスクリーン',
|
|
333
|
+
exitFullscreen: 'フルスクリーン終了',
|
|
334
|
+
enterPiP: 'ピクチャーインピクチャー',
|
|
335
|
+
exitPiP: 'ピクチャーインピクチャー終了',
|
|
336
|
+
enableCaptions: '字幕を有効化',
|
|
337
|
+
disableCaptions: '字幕を無効化',
|
|
338
|
+
captions: '字幕',
|
|
339
|
+
captionsOff: 'オフ',
|
|
340
|
+
settings: '設定',
|
|
341
|
+
quality: '画質',
|
|
342
|
+
auto: '自動',
|
|
343
|
+
speed: '再生速度',
|
|
344
|
+
normal: '通常',
|
|
345
|
+
loop: 'ループ',
|
|
346
|
+
loopEnabled: 'ループ有効',
|
|
347
|
+
loopDisabled: 'ループ無効',
|
|
348
|
+
audioBoost: 'オーディオブースト',
|
|
349
|
+
audioTrack: 'オーディオトラック',
|
|
350
|
+
live: 'ライブ',
|
|
351
|
+
liveEdge: 'ライブ中',
|
|
352
|
+
seekToLive: 'ライブに移動',
|
|
353
|
+
behindLive: '{seconds}秒遅れ',
|
|
354
|
+
networkError: 'ネットワークエラー',
|
|
355
|
+
mediaError: 'メディアを読み込めません',
|
|
356
|
+
unknownError: '不明なエラー',
|
|
357
|
+
loading: '読み込み中',
|
|
358
|
+
buffering: 'バッファリング',
|
|
359
|
+
chapters: 'チャプター',
|
|
360
|
+
airPlay: 'AirPlay',
|
|
361
|
+
googleCast: 'キャスト',
|
|
362
|
+
casting: '{device}にキャスト中',
|
|
363
|
+
download: 'ダウンロード',
|
|
364
|
+
share: '共有',
|
|
365
|
+
close: '閉じる',
|
|
366
|
+
menu: 'メニュー',
|
|
367
|
+
back: '戻る',
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export const chineseStrings: TranslationStrings = {
|
|
371
|
+
play: '播放',
|
|
372
|
+
pause: '暂停',
|
|
373
|
+
replay: '重播',
|
|
374
|
+
mute: '静音',
|
|
375
|
+
unmute: '取消静音',
|
|
376
|
+
volume: '音量',
|
|
377
|
+
seekBackward: '后退{seconds}秒',
|
|
378
|
+
seekForward: '前进{seconds}秒',
|
|
379
|
+
seekTo: '跳转到{time}',
|
|
380
|
+
duration: '时长',
|
|
381
|
+
currentTime: '当前时间',
|
|
382
|
+
played: '已播放',
|
|
383
|
+
buffered: '已缓冲',
|
|
384
|
+
enterFullscreen: '全屏',
|
|
385
|
+
exitFullscreen: '退出全屏',
|
|
386
|
+
enterPiP: '画中画',
|
|
387
|
+
exitPiP: '退出画中画',
|
|
388
|
+
enableCaptions: '开启字幕',
|
|
389
|
+
disableCaptions: '关闭字幕',
|
|
390
|
+
captions: '字幕',
|
|
391
|
+
captionsOff: '关闭',
|
|
392
|
+
settings: '设置',
|
|
393
|
+
quality: '画质',
|
|
394
|
+
auto: '自动',
|
|
395
|
+
speed: '播放速度',
|
|
396
|
+
normal: '正常',
|
|
397
|
+
loop: '循环',
|
|
398
|
+
loopEnabled: '循环已开启',
|
|
399
|
+
loopDisabled: '循环已关闭',
|
|
400
|
+
audioBoost: '音频增强',
|
|
401
|
+
audioTrack: '音轨',
|
|
402
|
+
live: '直播',
|
|
403
|
+
liveEdge: '直播中',
|
|
404
|
+
seekToLive: '跳转到直播',
|
|
405
|
+
behindLive: '落后{seconds}秒',
|
|
406
|
+
networkError: '网络错误',
|
|
407
|
+
mediaError: '无法加载媒体',
|
|
408
|
+
unknownError: '未知错误',
|
|
409
|
+
loading: '加载中',
|
|
410
|
+
buffering: '缓冲中',
|
|
411
|
+
chapters: '章节',
|
|
412
|
+
airPlay: 'AirPlay',
|
|
413
|
+
googleCast: '投射',
|
|
414
|
+
casting: '正在投射到{device}',
|
|
415
|
+
download: '下载',
|
|
416
|
+
share: '分享',
|
|
417
|
+
close: '关闭',
|
|
418
|
+
menu: '菜单',
|
|
419
|
+
back: '返回',
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export const defaultTranslations: Record<string, TranslationStrings> = {
|
|
423
|
+
en: englishStrings,
|
|
424
|
+
es: spanishStrings,
|
|
425
|
+
fr: frenchStrings,
|
|
426
|
+
de: germanStrings,
|
|
427
|
+
ja: japaneseStrings,
|
|
428
|
+
zh: chineseStrings,
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// =============================================================================
|
|
432
|
+
// I18n Class
|
|
433
|
+
// =============================================================================
|
|
434
|
+
|
|
435
|
+
export class I18n {
|
|
436
|
+
private language: string
|
|
437
|
+
private fallbackLanguage: string
|
|
438
|
+
private translations: Record<string, Partial<TranslationStrings>>
|
|
439
|
+
private interpolationPattern: RegExp
|
|
440
|
+
|
|
441
|
+
constructor(config: I18nConfig = {}) {
|
|
442
|
+
this.language = config.language || this.detectLanguage() || 'en'
|
|
443
|
+
this.fallbackLanguage = config.fallbackLanguage || 'en'
|
|
444
|
+
this.translations = { ...defaultTranslations }
|
|
445
|
+
|
|
446
|
+
// Merge custom translations
|
|
447
|
+
if (config.translations) {
|
|
448
|
+
for (const [lang, strings] of Object.entries(config.translations)) {
|
|
449
|
+
if (strings) {
|
|
450
|
+
this.translations[lang] = { ...this.translations[lang], ...strings }
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
this.interpolationPattern = config.interpolationPattern || /\{(\w+)\}/g
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Detect browser language
|
|
460
|
+
*/
|
|
461
|
+
private detectLanguage(): string | null {
|
|
462
|
+
if (typeof navigator === 'undefined') return null
|
|
463
|
+
|
|
464
|
+
const lang = navigator.language || (navigator as any).userLanguage
|
|
465
|
+
if (!lang) return null
|
|
466
|
+
|
|
467
|
+
// Try exact match first
|
|
468
|
+
if (this.translations[lang]) {
|
|
469
|
+
return lang
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Try base language (e.g., 'en' from 'en-US')
|
|
473
|
+
const baseLang = lang.split('-')[0]
|
|
474
|
+
if (this.translations[baseLang]) {
|
|
475
|
+
return baseLang
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return null
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Get current language
|
|
483
|
+
*/
|
|
484
|
+
getLanguage(): string {
|
|
485
|
+
return this.language
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Set current language
|
|
490
|
+
*/
|
|
491
|
+
setLanguage(language: string): void {
|
|
492
|
+
this.language = language
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Get translation for a key
|
|
497
|
+
*/
|
|
498
|
+
t(key: TranslationKey, params?: Record<string, string | number>): string {
|
|
499
|
+
// Try current language
|
|
500
|
+
let str = this.translations[this.language]?.[key]
|
|
501
|
+
|
|
502
|
+
// Fall back to fallback language
|
|
503
|
+
if (!str) {
|
|
504
|
+
str = this.translations[this.fallbackLanguage]?.[key]
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Return key if no translation found
|
|
508
|
+
if (!str) {
|
|
509
|
+
return key
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Interpolate params
|
|
513
|
+
if (params) {
|
|
514
|
+
str = str.replace(this.interpolationPattern, (match, paramKey) => {
|
|
515
|
+
const value = params[paramKey]
|
|
516
|
+
return value !== undefined ? String(value) : match
|
|
517
|
+
})
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return str
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Add or update translations for a language
|
|
525
|
+
*/
|
|
526
|
+
addTranslations(language: string, strings: Partial<TranslationStrings>): void {
|
|
527
|
+
this.translations[language] = {
|
|
528
|
+
...this.translations[language],
|
|
529
|
+
...strings,
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Get all translations for a language
|
|
535
|
+
*/
|
|
536
|
+
getTranslations(language: string): Partial<TranslationStrings> | undefined {
|
|
537
|
+
return this.translations[language]
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Get all available languages
|
|
542
|
+
*/
|
|
543
|
+
getAvailableLanguages(): string[] {
|
|
544
|
+
return Object.keys(this.translations)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Check if a language is available
|
|
549
|
+
*/
|
|
550
|
+
hasLanguage(language: string): boolean {
|
|
551
|
+
return language in this.translations
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// =============================================================================
|
|
556
|
+
// Factory
|
|
557
|
+
// =============================================================================
|
|
558
|
+
|
|
559
|
+
let globalI18n: I18n | null = null
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Create an I18n instance
|
|
563
|
+
*/
|
|
564
|
+
export function createI18n(config?: I18nConfig): I18n {
|
|
565
|
+
return new I18n(config)
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Get or create global I18n instance
|
|
570
|
+
*/
|
|
571
|
+
export function getI18n(config?: I18nConfig): I18n {
|
|
572
|
+
if (!globalI18n) {
|
|
573
|
+
globalI18n = createI18n(config)
|
|
574
|
+
}
|
|
575
|
+
return globalI18n
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Set global I18n instance
|
|
580
|
+
*/
|
|
581
|
+
export function setI18n(i18n: I18n): void {
|
|
582
|
+
globalI18n = i18n
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Quick translation helper using global instance
|
|
587
|
+
*/
|
|
588
|
+
export function t(key: TranslationKey, params?: Record<string, string | number>): string {
|
|
589
|
+
return getI18n().t(key, params)
|
|
590
|
+
}
|