@mindedge/vuetify-player 0.3.1 → 0.4.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.
@@ -2,33 +2,40 @@
2
2
  <v-card>
3
3
  <v-card-title>{{ t(language, 'playlist.up_next') }}</v-card-title>
4
4
  <v-card-text>
5
- <v-list>
5
+ <v-list class="playlist-list">
6
6
  <v-list-item-group v-model="sourceIndex">
7
- <v-list-item
7
+ <v-tooltip
8
+ bottom
8
9
  v-for="(source, index) of playlist"
9
10
  :key="index + 'playlistSources'"
10
- @click="onPlaylistSelect(index)"
11
11
  >
12
- <v-list-item-icon>
13
- <v-avatar
14
- v-if="getPoster(source.poster, poster)"
15
- tile
12
+ <template #activator="{ on, attrs }">
13
+ <v-list-item
14
+ class="pl-1"
15
+ v-bind="attrs"
16
+ v-on="on"
17
+ @click="onPlaylistSelect(index)"
16
18
  >
17
- <img :src="getPoster(source.poster, poster)" />
18
- </v-avatar>
19
- <v-skeleton-loader
20
- v-if="!getPoster(source.poster, poster)"
21
- class="ma-3"
22
- type="avatar"
23
- tile
24
- ></v-skeleton-loader>
25
- </v-list-item-icon>
26
- <v-list-item-content>
27
- <v-tooltip bottom>
28
- <template v-slot:activator="{ on, attrs }">
19
+ <v-list-item-icon class="ma-2">
20
+ <v-avatar
21
+ v-if="getPoster(source.poster, poster)"
22
+ tile
23
+ >
24
+ <img
25
+ :src="
26
+ getPoster(source.poster, poster)
27
+ "
28
+ />
29
+ </v-avatar>
30
+ <v-skeleton-loader
31
+ v-if="!getPoster(source.poster, poster)"
32
+ class="ma-3"
33
+ type="avatar"
34
+ tile
35
+ ></v-skeleton-loader>
36
+ </v-list-item-icon>
37
+ <v-list-item-content>
29
38
  <div
30
- v-bind="attrs"
31
- v-on="on"
32
39
  class="text-lg-subtitle-1 text-truncate"
33
40
  >
34
41
  {{
@@ -36,16 +43,16 @@
36
43
  t(language, 'playlist.default_name')
37
44
  }}
38
45
  </div>
39
- </template>
40
- <span>
41
- {{
42
- source.name ||
43
- t(language, 'playlist.default_name')
44
- }}
45
- </span>
46
- </v-tooltip>
47
- </v-list-item-content>
48
- </v-list-item>
46
+ </v-list-item-content>
47
+ </v-list-item>
48
+ </template>
49
+ <span>
50
+ {{
51
+ source.name ||
52
+ t(language, 'playlist.default_name')
53
+ }}
54
+ </span>
55
+ </v-tooltip>
49
56
  </v-list-item-group>
50
57
  </v-list>
51
58
  </v-card-text>
@@ -122,17 +129,8 @@ export default {
122
129
  </script>
123
130
 
124
131
  <style scoped>
125
- .captions-list {
126
- max-height: 10em;
132
+ .playlist-list {
133
+ max-height: 200px;
127
134
  overflow-y: scroll;
128
- /* Fade the top/bottom 20% effect. The "red" mask is so the scrollbar doesn't get this effect*/
129
- mask: linear-gradient(90deg, rgba(255, 0, 0, 0) 98%, rgba(255, 0, 0, 1) 98%),
130
- linear-gradient(
131
- 0deg,
132
- rgba(0, 0, 0, 0) 0%,
133
- rgba(0, 0, 0, 1) 20%,
134
- rgba(0, 0, 0, 1) 80%,
135
- rgba(0, 0, 0, 0) 100%
136
- );
137
135
  }
138
136
  </style>
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <!-- Settings -->
3
+ <v-menu :attach="attach" top left offset-y :close-on-content-click="false">
4
+ <template #activator="{ on, attrs }">
5
+ <v-btn small text v-bind="attrs" v-on="on">
6
+ <v-icon>mdi-cog</v-icon>
7
+ <span class="d-sr-only">{{
8
+ t(language, 'player.toggle_settings')
9
+ }}</span>
10
+ </v-btn>
11
+ </template>
12
+
13
+ <v-list>
14
+ <v-list-item v-if="attributes.captionsmenu">
15
+ <v-list-item-title>
16
+ <v-switch
17
+ :input-value="captionsVisible"
18
+ :label="t(language, 'captions.show_transcript')"
19
+ @change="$emit('update:captions-visible', $event)"
20
+ ></v-switch>
21
+ </v-list-item-title>
22
+ </v-list-item>
23
+ <v-list-item>
24
+ <v-list-item-title>
25
+ <v-icon>mdi-play-speed</v-icon>
26
+ {{ t(language, 'player.playback_speed') }}
27
+ </v-list-item-title>
28
+ </v-list-item>
29
+ <v-list-item>
30
+ <v-list-item-title class="text-center">
31
+ <v-btn
32
+ small
33
+ :disabled="state.playbackRateIndex === 0"
34
+ @click="onPlaybackSpeed(state.playbackRateIndex - 1)"
35
+ >
36
+ <v-icon> mdi-clock-minus-outline </v-icon>
37
+ <span class="d-sr-only">{{
38
+ t(language, 'player.playback_decrease')
39
+ }}</span>
40
+ </v-btn>
41
+ <span class="pl-2 pr-2"
42
+ >{{
43
+ attributes.playbackrates[state.playbackRateIndex]
44
+ }}x</span
45
+ >
46
+ <v-btn
47
+ small
48
+ :disabled="
49
+ state.playbackRateIndex >=
50
+ attributes.playbackrates.length - 1
51
+ "
52
+ @click="onPlaybackSpeed(state.playbackRateIndex + 1)"
53
+ >
54
+ <v-icon> mdi-clock-plus-outline </v-icon>
55
+ <span class="d-sr-only">{{
56
+ t(language, 'player.playback_increase')
57
+ }}</span>
58
+ </v-btn>
59
+ </v-list-item-title>
60
+ </v-list-item>
61
+ </v-list>
62
+ </v-menu>
63
+ </template>
64
+
65
+ <script>
66
+ import { t } from '../../i18n/i18n'
67
+
68
+ export default {
69
+ name: 'SettingsMenu',
70
+ components: {},
71
+ props: {
72
+ language: { type: String, required: false, default: 'en-US' },
73
+ attach: { type: null, required: false, default: false },
74
+ state: {
75
+ type: Object,
76
+ required: true,
77
+ },
78
+ attributes: {
79
+ type: Object,
80
+ required: true,
81
+ },
82
+ captionsVisible: { type: Boolean, required: false, default: undefined },
83
+ },
84
+ emits: ['update:captions-visible', 'change:playback-rate-index'],
85
+ watch: {},
86
+ computed: {},
87
+ data() {
88
+ return { t }
89
+ },
90
+ beforeMount() {},
91
+ mounted() {},
92
+ methods: {
93
+ onPlaybackSpeed(index) {
94
+ this.$emit('change:playback-rate-index', index)
95
+ },
96
+ },
97
+ }
98
+ </script>
@@ -34,9 +34,13 @@ export default {
34
34
  watch: {},
35
35
  computed: {
36
36
  playerClass() {
37
- let classList = 'player-' + this.type
37
+ let classList = 'player-' + this.resolvedType
38
38
  return classList
39
39
  },
40
+ resolvedType() {
41
+ // Youtube is always a video
42
+ return 'video'
43
+ },
40
44
  },
41
45
  data() {
42
46
  return {
@@ -1,7 +1,23 @@
1
1
  <template>
2
2
  <div>
3
- <v-row>
4
- <v-col :cols="playerCols">
3
+ <v-row tabindex="0">
4
+ <v-col cols="12">
5
+ <div v-if="parseSourceType(current.src.sources) === null">
6
+ <div class="player-skeleton--no-source">
7
+ <slot name="no-source">
8
+ <div>
9
+ <v-icon x-large>mdi-cloud-question</v-icon>
10
+ <p>
11
+ {{ t(language, 'player.not_configured') }}
12
+ </p>
13
+ </div>
14
+ </slot>
15
+ </div>
16
+ <v-skeleton-loader
17
+ type="image, image, list-item-avatar"
18
+ class="player-skeleton"
19
+ ></v-skeleton-loader>
20
+ </div>
5
21
  <YoutubePlayer
6
22
  ref="youtubePlayer"
7
23
  v-if="parseSourceType(current.src.sources) === 'youtube'"
@@ -9,6 +25,8 @@
9
25
  :type="current.type"
10
26
  :attributes="current.attributes"
11
27
  :src="current.src"
28
+ @focusin="onFocusin"
29
+ @focusout="onFocusout"
12
30
  @click:fullscreen="onFullscreen"
13
31
  ></YoutubePlayer>
14
32
  <Html5Player
@@ -18,6 +36,13 @@
18
36
  :type="current.type"
19
37
  :attributes="current.attributes"
20
38
  :src="current.src"
39
+ :captions-expanded.sync="captionsExpandedState"
40
+ :captions-hide-expand="captionsHideExpand"
41
+ :captions-paragraph-view="captionsParagraphView"
42
+ :captions-hide-paragraph-view="captionsHideParagraphView"
43
+ :captions-autoscroll="captionsAutoscroll"
44
+ :captions-hide-autoscroll="captionsHideAutoscroll"
45
+ :captions-visible.sync="captionsVisibleState"
21
46
  @load="$emit('load', $event)"
22
47
  @ended="onEnded"
23
48
  @loadeddata="onLoadeddata"
@@ -37,19 +62,29 @@
37
62
  @abort="$emit('abort', $event)"
38
63
  @mouseover="$emit('mouseover', $event)"
39
64
  @mouseout="$emit('mouseout', $event)"
65
+ @update:captions-expanded="
66
+ $emit('update:captions-expanded', $event)
67
+ "
68
+ @update:captions-paragraph-view="
69
+ $emit('update:captions-paragraph-view', $event)
70
+ "
71
+ @update:captions-autoscroll="
72
+ $emit('update:captions-autoscroll', $event)
73
+ "
40
74
  @click:fullscreen="onFullscreen"
41
75
  @click:pictureinpicture="onPictureInPicture"
42
76
  @click:remoteplayback="onRemoteplayback"
43
77
  @click:captions-expand="onClickCaptionsExpand"
44
- @click:captions-paragraph="onClickCaptionsParagraph"
78
+ @click:captions-paragraph-view="onClickCaptionsParagraph"
79
+ @click:captions-autoscroll="onClickCaptionsAutoscroll"
80
+ @click:captions-close="onClickCaptionsClose"
81
+ @focusin="onFocusin"
82
+ @focusout="onFocusout"
45
83
  ></Html5Player>
46
84
  </v-col>
47
85
 
48
86
  <!-- Playlist stuff -->
49
- <v-col
50
- v-if="playlistmenu && playlist.length > 1"
51
- :cols="playlistCols"
52
- >
87
+ <v-col v-if="showPlaylist" cols="12" class="mt-0 pt-0">
53
88
  <PlaylistMenu
54
89
  v-model="sourceIndex"
55
90
  :language="language"
@@ -63,6 +98,7 @@
63
98
  </template>
64
99
 
65
100
  <script>
101
+ import { t } from '../i18n/i18n'
66
102
  import YoutubePlayer from './Media/YoutubePlayer.vue'
67
103
  import Html5Player from './Media/Html5Player.vue'
68
104
  import PlaylistMenu from './Media/PlaylistMenu.vue'
@@ -90,7 +126,7 @@ export default {
90
126
  return []
91
127
  },
92
128
  },
93
- type: { type: String, required: false, default: 'video' }, // Allowed video|audio. In audio mode the player has a max-height of 40px
129
+ type: { type: String, required: false, default: 'auto' }, // Allowed auto|video|audio. In audio mode the player has a max-height of 40px
94
130
  autoplay: { type: Boolean, required: false, default: false }, // Autoplay on load. It's in the spec but DON'T USE THIS
95
131
  autopictureinpicture: {
96
132
  type: Boolean,
@@ -123,6 +159,42 @@ export default {
123
159
  poster: { type: String, required: false, default: '' }, // Overridden with the playlist.poster if one is set there
124
160
  preload: { type: String, required: false, default: '' },
125
161
  captionsmenu: { type: Boolean, required: false, default: true }, // Show the captions below the video
162
+ captionsExpanded: {
163
+ type: Boolean,
164
+ required: false,
165
+ default: undefined,
166
+ },
167
+ captionsHideExpand: { type: Boolean, required: false, default: true },
168
+ captionsParagraphView: {
169
+ type: Boolean,
170
+ required: false,
171
+ default: undefined,
172
+ },
173
+ captionsHideParagraphView: {
174
+ type: Boolean,
175
+ required: false,
176
+ default: false,
177
+ },
178
+ captionsAutoscroll: {
179
+ type: Boolean,
180
+ required: false,
181
+ default: undefined,
182
+ },
183
+ captionsHideAutoscroll: {
184
+ type: Boolean,
185
+ required: false,
186
+ default: false,
187
+ },
188
+ captionsHideClose: {
189
+ type: Boolean,
190
+ required: false,
191
+ default: false,
192
+ },
193
+ captionsVisible: {
194
+ type: Boolean,
195
+ required: false,
196
+ default: true,
197
+ },
126
198
  playlistmenu: { type: Boolean, required: false, default: true }, // Show the playlist menu if there's multiple videos
127
199
  playlistautoadvance: { type: Boolean, required: false, default: true }, // Play the next source group
128
200
  playbackrates: {
@@ -133,6 +205,37 @@ export default {
133
205
  },
134
206
  }, // Default playback speeds
135
207
  },
208
+ emits: [
209
+ 'load',
210
+ 'loadeddata',
211
+ 'loadedmetadata',
212
+ 'play',
213
+ 'pause',
214
+ 'seeking',
215
+ 'timeupdate',
216
+ 'progress',
217
+ 'canplay',
218
+ 'waiting',
219
+ 'canplaythrough',
220
+ 'error',
221
+ 'emptied',
222
+ 'ratechange',
223
+ 'stalled',
224
+ 'abort',
225
+ 'mouseover',
226
+ 'mouseout',
227
+ 'ended',
228
+ 'click:pictureinpicture',
229
+ 'click:fullscreen',
230
+ 'click:captions-expand',
231
+ 'click:captions-paragraph-view',
232
+ 'click:captions-autoscroll',
233
+ 'click:captions-close',
234
+ 'update:captions-expanded',
235
+ 'update:captions-paragraph-view',
236
+ 'update:captions-autoscroll',
237
+ 'update:captions-visible',
238
+ ],
136
239
  watch: {},
137
240
  computed: {
138
241
  player() {
@@ -180,17 +283,9 @@ export default {
180
283
  },
181
284
  playlistCols() {
182
285
  // Captions collapsed, playlist will appear on the right
183
- if (
184
- !this.captionsExpanded &&
185
- this.playlistmenu &&
186
- this.playlist.length > 1
187
- ) {
286
+ if (!this.captionsExpandedState && this.showPlaylist) {
188
287
  return 4
189
- } else if (
190
- this.captionsExpanded &&
191
- this.playlistmenu &&
192
- this.playlist.length > 1
193
- ) {
288
+ } else if (this.captionsExpandedState && this.showPlaylist) {
194
289
  // Captions expanded, playlist will appear as a new row on the bottom of everything
195
290
  return 12
196
291
  } else {
@@ -198,21 +293,52 @@ export default {
198
293
  }
199
294
  },
200
295
  playerCols() {
201
- if (
202
- this.captionsExpanded ||
203
- !this.playlistmenu ||
204
- this.playlist.length <= 1
205
- ) {
296
+ if (this.captionsExpandedState || !this.showPlaylist) {
206
297
  return 12
207
298
  } else {
208
299
  return 8
209
300
  }
210
301
  },
302
+ captionsVisibleState: {
303
+ get() {
304
+ if (typeof this.captionsVisible !== 'undefined') {
305
+ return this.captionsVisible
306
+ } else {
307
+ return this.captions.visible
308
+ }
309
+ },
310
+ set(v) {
311
+ this.$emit('update:captions-visible', v)
312
+ this.captions.visible = v
313
+ },
314
+ },
315
+ captionsExpandedState: {
316
+ get() {
317
+ if (typeof this.captionsExpanded !== 'undefined') {
318
+ return this.captionsExpanded
319
+ } else {
320
+ return this.captions.expanded
321
+ }
322
+ },
323
+ set(v) {
324
+ this.$emit('update:captions-expanded', v)
325
+ this.captions.expanded = v
326
+ },
327
+ },
328
+ showPlaylist() {
329
+ return this.playlistmenu && this.playlist.length > 1
330
+ },
211
331
  },
212
332
  data() {
213
333
  return {
334
+ t,
214
335
  sourceIndex: 0,
215
- captionsExpanded: false,
336
+ captions: {
337
+ visible: true,
338
+ expanded: false,
339
+ },
340
+ mediaFocus: false,
341
+ keyListener: null,
216
342
  }
217
343
  },
218
344
  methods: {
@@ -273,16 +399,25 @@ export default {
273
399
  }
274
400
  },
275
401
  onClickCaptionsExpand(expanded) {
276
- this.captionsExpanded = expanded
277
402
  this.$emit('click:captions-expand', expanded)
278
403
  },
279
404
  onClickCaptionsParagraph(isParagraph) {
280
- this.$emit('click:captions-paragraph', isParagraph)
405
+ this.$emit('click:captions-paragraph-view', isParagraph)
406
+ },
407
+ onClickCaptionsAutoscroll(autoscroll) {
408
+ this.$emit('click:captions-autoscroll', autoscroll)
409
+ },
410
+ onClickCaptionsClose() {
411
+ this.$emit('click:captions-close')
281
412
  },
282
413
  onPlaylistSelect(index) {
283
414
  this.sourceIndex = parseInt(index)
284
- this.player.load()
285
- this.player.play()
415
+
416
+ // If we give a bad media type then the player won't resolve
417
+ if (this.player && typeof this.player.load !== 'undefined') {
418
+ this.player.load()
419
+ this.player.play()
420
+ }
286
421
  },
287
422
  parseSourceType(sources) {
288
423
  const ytRegex =
@@ -304,6 +439,44 @@ export default {
304
439
  return 'html5'
305
440
  }
306
441
  },
442
+ onFocusin() {
443
+ this.mediaFocus = true
444
+ if (this.player && this.player.$el) {
445
+ this.player.$el.addEventListener('keydown', this.onKeydown)
446
+ }
447
+ },
448
+ onFocusout() {
449
+ this.mediaFocus = false
450
+ if (this.player && this.player.$el) {
451
+ this.player.$el.removeEventListener('keydown', this.onKeydown)
452
+ }
453
+ },
454
+ onKeydown(e) {
455
+ // Only process keyboard events if the media is focused
456
+ // This is just in case the media lost focus but the event listener wasn't removed for some reason
457
+ if (this.mediaFocus) {
458
+ e.preventDefault()
459
+ const map = {
460
+ Space: { cb: this.player.playToggle, params: [e] },
461
+ KeyK: { cb: this.player.playToggle, params: [e] },
462
+ KeyM: { cb: this.player.muteToggle, params: [e] },
463
+ ArrowLeft: { cb: this.player.rewind, params: [5] },
464
+ ArrowRight: { cb: this.player.fastForward, params: [5] },
465
+ KeyJ: { cb: this.player.rewind, params: [10] },
466
+ KeyL: { cb: this.player.fastForward, params: [10] },
467
+ ArrowUp: { cb: this.player.volumeAdjust, params: [0.1] },
468
+ ArrowDown: { cb: this.player.volumeAdjust, params: [-0.1] },
469
+ KeyF: { cb: this.player.fullscreenToggle, params: [e] },
470
+ KeyC: { cb: this.player.CCToggle, params: [e] },
471
+ }
472
+ if (
473
+ typeof map[e.code] !== 'undefined' &&
474
+ typeof map[e.code].cb !== 'undefined'
475
+ ) {
476
+ map[e.code].cb(...map[e.code].params)
477
+ }
478
+ }
479
+ },
307
480
  },
308
481
  beforeCreate() {},
309
482
  beforeMount() {},
@@ -311,3 +484,16 @@ export default {
311
484
  beforeDestroy() {},
312
485
  }
313
486
  </script>
487
+
488
+ <style scoped>
489
+ .player-skeleton {
490
+ aspect-ratio: 16 / 9;
491
+ overflow: hidden;
492
+ }
493
+ .player-skeleton--no-source {
494
+ height: 0px;
495
+ position: relative;
496
+ top: 100px;
497
+ text-align: center;
498
+ }
499
+ </style>
package/src/i18n/en-US.js CHANGED
@@ -10,6 +10,7 @@ export default {
10
10
  next: 'Play next item in playlist',
11
11
  },
12
12
  player: {
13
+ not_configured: 'Media not configured',
13
14
  playback_speed: 'Playback Speed',
14
15
  playback_decrease: 'Decrease playback speed',
15
16
  playback_increase: 'Increase playback speed',
@@ -27,9 +28,17 @@ export default {
27
28
  no_support: "Sorry, your browser doesn't support embedded videos.",
28
29
  },
29
30
  captions: {
31
+ show_transcript: 'Show Transcript',
32
+ close: 'Close',
33
+ search: 'Search',
34
+ none_found: "No captions found for '{0}'",
30
35
  expand: 'Expand',
31
36
  collapse: 'Collapse',
32
37
  view_as_paragraph: 'View as paragraph',
33
38
  view_as_captions: 'View as captions',
39
+ enable_autoscroll: 'Enable auto-scroll for transcript as media plays',
40
+ disable_autoscroll: 'Disable auto-scroll for transcript as media plays',
41
+ autoscroll_enabled: 'Autoscroll transcript enabled',
42
+ autoscroll_disabled: 'Autoscroll transcript disabled',
34
43
  },
35
44
  }
package/src/i18n/es-ES.js CHANGED
@@ -10,6 +10,7 @@ export default {
10
10
  next: 'Reproducir el siguiente elemento en la lista de reproducción',
11
11
  },
12
12
  player: {
13
+ not_configured: 'Medios no configurados',
13
14
  playback_speed: 'Velocidad de reproducción',
14
15
  playback_decrease: 'Disminuir la velocidad de reproducción',
15
16
  playback_increase: 'Aumentar la velocidad de reproducción',
@@ -27,9 +28,20 @@ export default {
27
28
  no_support: 'Lo sentimos, su navegador no admite vídeos incrustados. ',
28
29
  },
29
30
  captions: {
31
+ show_transcript: 'Mostrar transcripción',
32
+ close: 'Cerca',
33
+ search: 'Buscar',
34
+ none_found: "No se encontraron subtítulos para '{0}'",
30
35
  expand: 'Expandir',
31
36
  collapse: 'Colapsar',
32
37
  view_as_paragraph: 'Ver como párrafo',
33
38
  view_as_captions: 'Ver como subtítulos',
39
+ enable_autoscroll:
40
+ 'Habilite el desplazamiento automático para la transcripción mientras se reproducen los medios',
41
+ disable_autoscroll:
42
+ 'Deshabilite el desplazamiento automático para la transcripción mientras se reproducen los medios',
43
+ autoscroll_enabled:
44
+ 'Transcripción con desplazamiento automático habilitada',
45
+ autoscroll_disabled: 'Transcripción automática deshabilitado',
34
46
  },
35
47
  }
package/src/i18n/i18n.js CHANGED
@@ -18,7 +18,7 @@ function get(obj, path) {
18
18
  return get(obj[parts[0]], parts.slice(1).join('.'))
19
19
  }
20
20
 
21
- const t = (lang, path) => {
21
+ const t = (lang, path, replacements = []) => {
22
22
  if (typeof i18n[lang] === 'undefined') {
23
23
  console.warn(
24
24
  '[VuetifyPlayer] No support for locale ' +
@@ -35,6 +35,11 @@ const t = (lang, path) => {
35
35
  console.warn(
36
36
  '[VuetifyPlayer] localization path ' + path + ' does not exist'
37
37
  )
38
+ } else {
39
+ // Apply replacements
40
+ for (const key in replacements) {
41
+ localized = localized.replaceAll('{' + key + '}', replacements[key])
42
+ }
38
43
  }
39
44
 
40
45
  return localized
package/src/i18n/sv-SE.js CHANGED
@@ -10,6 +10,7 @@ export default {
10
10
  next: 'Spela nästa',
11
11
  },
12
12
  player: {
13
+ not_configured: 'Media inte konfigurerad',
13
14
  playback_speed: 'Uppspelningshastighet',
14
15
  playback_decrease: 'Minska uppspelningshastigheten',
15
16
  playback_increase: 'Öka uppspelningshastigheten',
@@ -27,9 +28,19 @@ export default {
27
28
  no_support: 'Tyvärr, din webbläsare stöder inte inbäddade videor.',
28
29
  },
29
30
  captions: {
31
+ show_transcript: 'Visa avskrift',
32
+ close: 'Stäng',
33
+ search: 'Sök',
34
+ none_found: "Inga bildtexter hittades för '{0}'",
30
35
  expand: 'Bygga ut',
31
36
  collapse: 'Kollaps',
32
37
  view_as_paragraph: 'Visa som stycke',
33
38
  view_as_captions: 'Visa som bildtexter',
39
+ enable_autoscroll:
40
+ 'Aktivera automatisk rullning för transkription när media spelas upp',
41
+ disable_autoscroll:
42
+ 'Inaktivera automatisk rullning för transkribering när media spelas upp',
43
+ autoscroll_enabled: 'Autoscroll-transkription aktiverad',
44
+ autoscroll_disabled: 'Autoscroll-transkription inaktiverad',
34
45
  },
35
46
  }