summaryrefslogtreecommitdiff
path: root/extensions/TimedMediaHandler/MwEmbedModules/TimedText
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/TimedMediaHandler/MwEmbedModules/TimedText')
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php31
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js52
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php21
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json13
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json25
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json18
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json25
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json19
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json25
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json11
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json18
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js504
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js1313
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css18
83 files changed, 3448 insertions, 0 deletions
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php
new file mode 100644
index 00000000..46547697
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php
@@ -0,0 +1,31 @@
+<?php
+ /**
+ * Do not edit this file instead use LocalSettings.php and
+ * $wgMwEmbedModuleConfig[ {configuration name} ] = value; format
+ */
+
+ return array(
+ // If the Timed Text interface should be displayed:
+ // 'always' Displays link and call to contribute always
+ // 'auto' Looks for child timed text elements or "apiTitleKey" & load interface
+ // 'off' Does not display the timed text interface
+ "TimedText.ShowInterface" => "auto",
+
+ /**
+ * If the "add timed text" link / interface should be exposed
+ * allows usere to upload text files to the wiki
+ */
+ 'TimedText.ShowAddTextLink' => false,
+
+ // If the link to request a transcript should be shown on video files
+ 'TimedText.ShowRequestTranscript' => false,
+
+ // The category for listing videos that need transcription:
+ 'TimedText.NeedsTranscriptCategory' => 'Videos needing subtitles',
+
+ // The default bottom text padding
+ 'TimedText.BottomPadding' => 10,
+
+ // Height of black box below video.
+ 'TimedText.BelowVideoBlackBoxHeight' => 40
+ );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js
new file mode 100644
index 00000000..bbd62d0e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js
@@ -0,0 +1,52 @@
+/**
+* TimedText loader.
+*/
+// Scope everything in "mw" ( keeps the global namespace clean )
+( function( mw, $ ) {
+
+ /**
+ * Check if the video tags in the page support timed text
+ * this way we can add our timed text libraries to the player
+ * library request.
+ */
+ // Update the player loader request with timedText library if the embedPlayer
+ // includes timedText tracks.
+ $( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, classRequest ) {
+ if( mw.isTimedTextSupported( playerElement ) ) {
+ classRequest = $.merge( classRequest, ['mw.TimedText'] );
+ }
+ } );
+ // On new embed player check if we need to add timedText
+ $( mw ).bind( 'EmbedPlayerNewPlayer', function( event, embedPlayer ){
+ if( mw.isTimedTextSupported( embedPlayer ) ){
+ embedPlayer.timedText = new mw.TimedText( embedPlayer );
+ }
+ });
+
+ /**
+ * Check timedText is active for a given embedPlayer
+ * @param {object} embedPlayer The player to be checked for timedText properties
+ */
+ mw.isTimedTextSupported = function( embedPlayer ) {
+ //EmbedPlayerNewPlayer passes a div with data-mwprovider set,
+ //EmbedPlayerUpdateDependencies passes video element with data attribute
+ //catch both
+ var mwprovider = embedPlayer['data-mwprovider'] || $( embedPlayer ).data('mwprovider');
+ var showInterface = mw.config.get( 'TimedText.ShowInterface.' + mwprovider ) ||
+ mw.config.get( 'TimedText.ShowInterface' );
+
+ if ( showInterface == 'always' ) {
+ return true;
+ } else if ( showInterface == 'off' ) {
+ return false;
+ }
+
+ // Check for standard 'track' attribute:
+ if ( $( embedPlayer ).find( 'track' ).length != 0 ) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php
new file mode 100644
index 00000000..57f50043
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php
@@ -0,0 +1,21 @@
+<?php
+
+ // Register all the timedText modules
+ return array(
+ "mw.TimedText" => array(
+ 'scripts' => "resources/mw.TimedText.js",
+ 'styles' => "resources/mw.style.TimedText.css",
+ 'dependencies' => array(
+ 'mw.EmbedPlayer',
+ 'mw.TextSource'
+ ),
+ 'messageDir' => 'i18n',
+ ),
+ "mw.TextSource" => array(
+ 'scripts' => "resources/mw.TextSource.js",
+ 'dependencies' => array(
+ 'mediawiki.UtilitiesTime',
+ "mw.ajaxProxy",
+ )
+ )
+ );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json
new file mode 100644
index 00000000..0024412a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Terug",
+ "mwe-timedtext-textcat-cc": "Onderskrifte",
+ "mwe-timedtext-textcat-lrc": "Lirieke"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json
new file mode 100644
index 00000000..48597e00
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meno25",
+ "روخو"
+ ]
+ },
+ "mwe-timedtext-back-btn": "رجوع",
+ "mwe-timedtext-layout-off": "إخفاء الترجمات",
+ "mwe-timedtext-loading-text": "جاري تحميل النص...",
+ "mwe-timedtext-textcat-cc": "نصوص توضيحية",
+ "mwe-timedtext-textcat-cue": "نقاط تلميح",
+ "mwe-timedtext-upload-timed-text": "إضافة الترجمات"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json
new file mode 100644
index 00000000..9df51f24
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Anterior",
+ "mwe-timedtext-layout-off": "Tapecer subtítulos",
+ "mwe-timedtext-loading-text": "Cargando'l testu...",
+ "mwe-timedtext-textcat-cc": "Lleendes",
+ "mwe-timedtext-textcat-sub": "Subtítulos",
+ "mwe-timedtext-textcat-tad": "Descripción del soníu",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Testu en movimientu",
+ "mwe-timedtext-textcat-ar": "Rexones actives",
+ "mwe-timedtext-textcat-nb": "Anotación",
+ "mwe-timedtext-textcat-meta": "Metadatos cronometraos",
+ "mwe-timedtext-textcat-trx": "Trescripción",
+ "mwe-timedtext-textcat-lrc": "Lletra",
+ "mwe-timedtext-textcat-lin": "Formatu llingüísticu",
+ "mwe-timedtext-textcat-cue": "Puntos de referencia",
+ "mwe-timedtext-no-subs": "Nun hai pistes de testu disponibles",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtítulos en $1 pal videu: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nun s'alcontraron los subtítulos en $1 pal videu: $2",
+ "mwe-timedtext-upload-timed-text": "Añadir subtítulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json
new file mode 100644
index 00000000..5c25527d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Jim-by",
+ "Wizardist"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Вярнуцца",
+ "mwe-timedtext-layout-off": "Схаваць субтытры",
+ "mwe-timedtext-loading-text": "Загрузка тэксту…",
+ "mwe-timedtext-textcat-cc": "Субтытры",
+ "mwe-timedtext-textcat-sub": "Субтытры:",
+ "mwe-timedtext-textcat-tad": "Аўдыя-апісаньне",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Тэкставыя карткі",
+ "mwe-timedtext-textcat-ar": "Актыўныя рэгіёны",
+ "mwe-timedtext-textcat-nb": "Анатацыя",
+ "mwe-timedtext-textcat-meta": "Сынхранізаваныя мета-зьвесткі",
+ "mwe-timedtext-textcat-trx": "Стэнаграма",
+ "mwe-timedtext-textcat-lrc": "Словы",
+ "mwe-timedtext-textcat-lin": "Лінгвістычная разьметка",
+ "mwe-timedtext-textcat-cue": "Сыгнальныя кропкі",
+ "mwe-timedtext-no-subs": "Субтытраў няма",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 субтытры для кліпу: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Субтытры $1 для кліпу ня знойдзеныя: $2",
+ "mwe-timedtext-upload-timed-text": "Дадаць субтытры"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json
new file mode 100644
index 00000000..b88de95d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json
new file mode 100644
index 00000000..395fbe7b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aftab1995",
+ "Bellayet"
+ ]
+ },
+ "mwe-timedtext-back-btn": "পিছনে",
+ "mwe-timedtext-layout-off": "উপশিরোনাম লুকাও",
+ "mwe-timedtext-loading-text": "টেক্সট লোড হচ্ছে ...",
+ "mwe-timedtext-textcat-cc": "পরিচয়লিপি",
+ "mwe-timedtext-textcat-sub": "উপশিরোনাম",
+ "mwe-timedtext-textcat-tad": "অডিও বিবরণ",
+ "mwe-timedtext-upload-timed-text": "উপশিরোনাম যুক্ত করুন"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json
new file mode 100644
index 00000000..eacd0f20
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fulup",
+ "Y-M D"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Distreiñ",
+ "mwe-timedtext-layout-off": "Kuzhat an istitloù",
+ "mwe-timedtext-loading-text": "O kargañ an destenn...",
+ "mwe-timedtext-textcat-cc": "Alc'hwezioù",
+ "mwe-timedtext-textcat-sub": "Istitloù",
+ "mwe-timedtext-textcat-tad": "Deskrivadur son",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Barenn titouroù",
+ "mwe-timedtext-textcat-ar": "Rannvroioù oberiant",
+ "mwe-timedtext-textcat-nb": "Notennadur",
+ "mwe-timedtext-textcat-meta": "Metaroadennoù sinkronelaet",
+ "mwe-timedtext-textcat-trx": "Treuzskrivañ",
+ "mwe-timedtext-textcat-lrc": "Komzoù",
+ "mwe-timedtext-textcat-lin": "Balizennoù yezhel",
+ "mwe-timedtext-textcat-cue": "Poent lec'hiañ",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 istitl evit ar c'hlip : $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "N'eo ket bet kavet $1 istitl evit ar c'hlip : $2",
+ "mwe-timedtext-upload-timed-text": "Enporzhiañ istitloù"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json
new file mode 100644
index 00000000..f8d0cd23
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Nazad",
+ "mwe-timedtext-textcat-sub": "Podnaslovi",
+ "mwe-timedtext-textcat-tad": "Opis zvuka"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json
new file mode 100644
index 00000000..ce45bfb5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pitort"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Enrere",
+ "mwe-timedtext-textcat-sub": "Subtítols"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json
new file mode 100644
index 00000000..f1580f0d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Умар"
+ ]
+ },
+ "mwe-timedtext-textcat-tad": "Аудио-хаам"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json
new file mode 100644
index 00000000..94a5e7eb
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mormegil",
+ "Vks"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zpět",
+ "mwe-timedtext-layout-off": "Skrýt titulky",
+ "mwe-timedtext-loading-text": "Načítá se text…",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-nb": "Anotace",
+ "mwe-timedtext-textcat-trx": "Přepis",
+ "mwe-timedtext-language-subtitles-for-clip": "Titulky ke klipu $2 v jazyce $1",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Ke klipu $2 nebyly nalezeny titulky v jazyce $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json
new file mode 100644
index 00000000..fd0eea45
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lloffiwr",
+ "Robin Owain"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Yn ôl",
+ "mwe-timedtext-layout-off": "Cuddio'r isdeitlau",
+ "mwe-timedtext-loading-text": "Yn llwytho'r testun...",
+ "mwe-timedtext-textcat-cc": "Geiriad",
+ "mwe-timedtext-textcat-sub": "Isdeitlau",
+ "mwe-timedtext-textcat-tad": "Disgrifiad o'r sain",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Testun",
+ "mwe-timedtext-textcat-ar": "Ardaloedd gweithredolo",
+ "mwe-timedtext-textcat-nb": "Anodiad",
+ "mwe-timedtext-textcat-meta": "Metadata a amserwyd",
+ "mwe-timedtext-textcat-trx": "Trawsysgrif",
+ "mwe-timedtext-textcat-lrc": "Geiriau",
+ "mwe-timedtext-textcat-cue": "Cerrig milltir",
+ "mwe-timedtext-no-subs": "Dim traciau testun ar gael",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 isdeitl ar gael ar gyfer clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Dim $1 isdeitl ar gael ar gyfer: $2",
+ "mwe-timedtext-upload-timed-text": "Ychwanegu isdeitlau"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json
new file mode 100644
index 00000000..10c9c650
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json
new file mode 100644
index 00000000..35d1cef9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln",
+ "Metalhead64",
+ "Purodha"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zurück",
+ "mwe-timedtext-layout-off": "Untertitel ausblenden",
+ "mwe-timedtext-loading-text": "Text wird geladen …",
+ "mwe-timedtext-textcat-cc": "Legenden",
+ "mwe-timedtext-textcat-sub": "Untertitel",
+ "mwe-timedtext-textcat-tad": "Beschreibung (Audio)",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text-Ticker",
+ "mwe-timedtext-textcat-ar": "Aktive Regionen",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "„Timed Text“-Metadaten",
+ "mwe-timedtext-textcat-trx": "Abschrift",
+ "mwe-timedtext-textcat-lrc": "Liedtext",
+ "mwe-timedtext-textcat-lin": "Sprachliche Beschreibung",
+ "mwe-timedtext-textcat-cue": "Cue-Punkte",
+ "mwe-timedtext-no-subs": "Es sind keine Untertitel verfügbar",
+ "mwe-timedtext-language-subtitles-for-clip": "Untertitel auf $1 für den Videoclip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Keine Untertitel auf $1 für den Videoclip gefunden: $2",
+ "mwe-timedtext-upload-timed-text": "Untertitel hinzufügen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json
new file mode 100644
index 00000000..ee86ed2c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erdemaslancan",
+ "Mirzali"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Peyser",
+ "mwe-timedtext-textcat-cc": "Bınnuşte",
+ "mwe-timedtext-textcat-sub": "Sernuştey bıni",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-nb": "Ole şınasiye"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json
new file mode 100644
index 00000000..362d95c8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Derbeth",
+ "Michawiki"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Slědk",
+ "mwe-timedtext-layout-off": "Pódtitele schowaś",
+ "mwe-timedtext-loading-text": "Tekst se zacytujo...",
+ "mwe-timedtext-textcat-cc": "Wopisanja",
+ "mwe-timedtext-textcat-sub": "Pódtitele",
+ "mwe-timedtext-textcat-tad": "Awdiowopisanje",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Běžecy tekst",
+ "mwe-timedtext-textcat-ar": "Aktiwne regiony",
+ "mwe-timedtext-textcat-nb": "Anotacija",
+ "mwe-timedtext-textcat-meta": "Synchronizěrowane metadaty",
+ "mwe-timedtext-textcat-trx": "Pśepisaś",
+ "mwe-timedtext-textcat-lrc": "Spiwny tekst",
+ "mwe-timedtext-textcat-lin": "Rěcywědne wopisanje",
+ "mwe-timedtext-textcat-cue": "Zastupne dypki",
+ "mwe-timedtext-no-subs": "Žedne pódtitele k dispoziciji",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 {{PLURAL:$1|pódtitel|pódtitela|pódtitele|oódtitelow}} za klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Žedne pódtitele $1 su se za klip namakali: $2",
+ "mwe-timedtext-upload-timed-text": "Pódtitele pśidaś"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json
new file mode 100644
index 00000000..9de04eff
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Geraki"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Επιστροφή",
+ "mwe-timedtext-layout-off": "Απόκρυψη υπότιτλων",
+ "mwe-timedtext-loading-text": "Φόρτωση κείμενου...",
+ "mwe-timedtext-textcat-cc": "Λεζάντες",
+ "mwe-timedtext-textcat-sub": "Υπότιτλοι",
+ "mwe-timedtext-textcat-tad": "Ακουστική περιγραφή",
+ "mwe-timedtext-textcat-ktv": "Καραόκε",
+ "mwe-timedtext-textcat-tik": "Κυλιόμενο κείμενο",
+ "mwe-timedtext-textcat-ar": "Ενεργές περιοχές",
+ "mwe-timedtext-textcat-nb": "Σχόλιο",
+ "mwe-timedtext-textcat-meta": "Χρονισμένα μεταδεδομένα",
+ "mwe-timedtext-textcat-trx": "Μεταγραφή",
+ "mwe-timedtext-textcat-lrc": "Στίχοι",
+ "mwe-timedtext-textcat-lin": "Γλωσσολογική σύνταξη",
+ "mwe-timedtext-textcat-cue": "Cue points",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 υπότιτλοι για το βίντεο: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Δεν βρέθηκαν υπότιτλοι $1 για το βίντεο: $2"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json
new file mode 100644
index 00000000..0505d5b7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": []
+ },
+ "mwe-timedtext-back-btn": "Back",
+ "mwe-timedtext-layout-off": "Hide subtitles",
+ "mwe-timedtext-loading-text": "Loading text ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Captions",
+ "mwe-timedtext-textcat-sub": "Subtitles",
+ "mwe-timedtext-textcat-tad": "Audio description",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Ticker text",
+ "mwe-timedtext-textcat-ar": "Active regions",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "Timed metadata",
+ "mwe-timedtext-textcat-trx": "Transcript",
+ "mwe-timedtext-textcat-lrc": "Lyrics",
+ "mwe-timedtext-textcat-lin": "Linguistic markup",
+ "mwe-timedtext-textcat-cue": "Cue points",
+ "mwe-timedtext-no-subs": "No text tracks available",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 subtitles for clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "No $1 subtitles were found for clip: $2",
+ "mwe-timedtext-upload-timed-text": "Add subtitles"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json
new file mode 100644
index 00000000..f787b8a6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yekrats"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json
new file mode 100644
index 00000000..e753ece1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armando-Martin",
+ "Crazymadlover",
+ "Locos epraix",
+ "Pertile",
+ "Translationista"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Atrás",
+ "mwe-timedtext-layout-off": "Ocultar subtítulos",
+ "mwe-timedtext-loading-text": "Cargando texto ...",
+ "mwe-timedtext-textcat-cc": "Leyendas",
+ "mwe-timedtext-textcat-sub": "Subtítulos",
+ "mwe-timedtext-textcat-tad": "Descripción de audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Texto desplazable",
+ "mwe-timedtext-textcat-ar": "Regiones activas",
+ "mwe-timedtext-textcat-nb": "Anotación",
+ "mwe-timedtext-textcat-meta": "Metadatos sincronizados",
+ "mwe-timedtext-textcat-trx": "Transcribir",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Marcador lingüístico",
+ "mwe-timedtext-textcat-cue": "Puntos de referencia",
+ "mwe-timedtext-no-subs": "No hay pistas de texto disponibles",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 subtítulos para el clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "No se ha encontrado subtítulos $1 para el clip: $2",
+ "mwe-timedtext-upload-timed-text": "Añadir subtítulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json
new file mode 100644
index 00000000..a57273aa
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Pikne"
+ ]
+ },
+ "mwe-timedtext-layout-off": "Peida alltiitrid",
+ "mwe-timedtext-loading-text": "Teksti laadimine...",
+ "mwe-timedtext-textcat-sub": "Alltiitrid",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-meta": "Ajastatud metaandmed",
+ "mwe-timedtext-textcat-lrc": "Laulusõnad",
+ "mwe-timedtext-no-subs": "Alltiitreid pole saadaval",
+ "mwe-timedtext-language-subtitles-for-clip": "Lõigu $2 $1 alltiitrid",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Lõigu $2 jaoks ei leitud $1 alltiitreid",
+ "mwe-timedtext-upload-timed-text": "Lisa alltiitrid"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json
new file mode 100644
index 00000000..5c30fe9d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද",
+ "Subi"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Atzera",
+ "mwe-timedtext-textcat-ktv": "Karaokea"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json
new file mode 100644
index 00000000..c6fa166e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armin1392",
+ "Ebraminio",
+ "Pouyana",
+ "Reza1615",
+ "پاناروما"
+ ]
+ },
+ "mwe-timedtext-back-btn": "بازگشت",
+ "mwe-timedtext-layout-off": "پنهان کردن زیرنویس",
+ "mwe-timedtext-loading-text": "در حال بارگیری متن ...",
+ "mwe-timedtext-textcat-cc": "عناوین:",
+ "mwe-timedtext-textcat-sub": "زیرنویس",
+ "mwe-timedtext-textcat-tad": "توضیح صوتی",
+ "mwe-timedtext-textcat-ktv": "کارائوکه",
+ "mwe-timedtext-textcat-tik": "متن تیکر",
+ "mwe-timedtext-textcat-ar": "مناطق فعال",
+ "mwe-timedtext-textcat-nb": "یادداشت",
+ "mwe-timedtext-textcat-meta": "فرادادهٔ به هنگام",
+ "mwe-timedtext-textcat-trx": "رونوشت",
+ "mwe-timedtext-textcat-lrc": "متن ترانه‌ها",
+ "mwe-timedtext-textcat-lin": "زبان نشانه‌گذاری",
+ "mwe-timedtext-textcat-cue": "نقاط نشانه",
+ "mwe-timedtext-no-subs": "هیچ آهنگ متنی دردسترس نیست",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 زیرنویس برای کلیپ: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "هیچ $1 زیرنویسی برای کلیپ پیدا نشد: $2",
+ "mwe-timedtext-upload-timed-text": "اضافه کردن زیرنویس"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json
new file mode 100644
index 00000000..e0fa5944
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nedergard",
+ "Nike",
+ "Silvonen"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Takaisin",
+ "mwe-timedtext-layout-off": "Piilota tekstitys",
+ "mwe-timedtext-loading-text": "Ladataan tekstiä...",
+ "mwe-timedtext-textcat-cc": "Kuvatekstit",
+ "mwe-timedtext-textcat-sub": "Tekstitykset",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-upload-timed-text": "Lisää tekstitys"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json
new file mode 100644
index 00000000..4e74e546
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "IAlex",
+ "Peter17",
+ "Tititou36",
+ "Verdy p"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Arrière",
+ "mwe-timedtext-layout-off": "Masquer les sous-titres",
+ "mwe-timedtext-loading-text": "Chargement du texte ...",
+ "mwe-timedtext-textcat-cc": "Légendes",
+ "mwe-timedtext-textcat-sub": "Sous-titres",
+ "mwe-timedtext-textcat-tad": "Description audio",
+ "mwe-timedtext-textcat-ktv": "Karaoké",
+ "mwe-timedtext-textcat-tik": "Barre d'informations",
+ "mwe-timedtext-textcat-ar": "Régions actives",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "métadonnées synchronisées",
+ "mwe-timedtext-textcat-trx": "Transcription",
+ "mwe-timedtext-textcat-lrc": "Paroles",
+ "mwe-timedtext-textcat-lin": "Balisage linguistique",
+ "mwe-timedtext-textcat-cue": "Points de repère",
+ "mwe-timedtext-no-subs": "Aucun texte de piste disponible",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 sous-titres pour clip : $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Aucun sous-titre $1 n'a été trouvé pour le clip : $2",
+ "mwe-timedtext-upload-timed-text": "Ajouter des sous-titres"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json
new file mode 100644
index 00000000..eeb629b9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Tornar",
+ "mwe-timedtext-layout-off": "Cachiér los sot-titros",
+ "mwe-timedtext-loading-text": "Chargement du tèxto ...",
+ "mwe-timedtext-textcat-cc": "Lègendes",
+ "mwe-timedtext-textcat-sub": "Sot-titros",
+ "mwe-timedtext-textcat-tad": "Dèscripcion ôdiô",
+ "mwe-timedtext-textcat-ktv": "Caraoquè",
+ "mwe-timedtext-textcat-tik": "Bârra d’enformacions",
+ "mwe-timedtext-textcat-ar": "Règ·ions actives",
+ "mwe-timedtext-textcat-nb": "Nota",
+ "mwe-timedtext-textcat-meta": "Mètabalyês sincronisâs",
+ "mwe-timedtext-textcat-trx": "Transcripcion",
+ "mwe-timedtext-textcat-lrc": "Paroles",
+ "mwe-timedtext-textcat-lin": "Balisâjo lengouistico",
+ "mwe-timedtext-textcat-cue": "Pouents de repèro",
+ "mwe-timedtext-no-subs": "Gins de pista de tèxto disponibla",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 sot-titros por clipe : $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nion sot-titro $1 at étâ trovâ por lo clipe : $2",
+ "mwe-timedtext-upload-timed-text": "Apondre des sot-titros"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json
new file mode 100644
index 00000000..69f89218
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Foarige"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json
new file mode 100644
index 00000000..df9d0409
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Volver",
+ "mwe-timedtext-layout-off": "Agochar os subtítulos",
+ "mwe-timedtext-loading-text": "Cargando o texto...",
+ "mwe-timedtext-textcat-cc": "Pés de foto",
+ "mwe-timedtext-textcat-sub": "Subtítulos",
+ "mwe-timedtext-textcat-tad": "Descrición do son",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Barra de información",
+ "mwe-timedtext-textcat-ar": "Rexións activas",
+ "mwe-timedtext-textcat-nb": "Anotación",
+ "mwe-timedtext-textcat-meta": "Metadatos sincronizados",
+ "mwe-timedtext-textcat-trx": "Transcrición",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Formato lingüístico",
+ "mwe-timedtext-textcat-cue": "Puntos de sinal",
+ "mwe-timedtext-no-subs": "Non hai pistas de texto dispoñibles",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtítulos en $1 para o vídeo: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Non se atoparon os subtítulos en $1 para o vídeo: $2",
+ "mwe-timedtext-upload-timed-text": "Engadir subtítulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json
new file mode 100644
index 00000000..c48c3c0c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Chlämens",
+ "Als-Holder"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zruck",
+ "mwe-timedtext-layout-off": "Untertitel uusblände",
+ "mwe-timedtext-loading-text": "Am Lade vum Text ...",
+ "mwe-timedtext-textcat-cc": "Bschryybige",
+ "mwe-timedtext-textcat-sub": "Untertitel",
+ "mwe-timedtext-textcat-tad": "Audio-Bschryybig",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text-Ticker",
+ "mwe-timedtext-textcat-ar": "Aktivi Regione",
+ "mwe-timedtext-textcat-nb": "Aamerkig",
+ "mwe-timedtext-textcat-meta": "Ächtzyt-Metadate",
+ "mwe-timedtext-textcat-trx": "Abschrift",
+ "mwe-timedtext-textcat-lrc": "Liedtext",
+ "mwe-timedtext-textcat-lin": "Sprochwisseschaftligi Bschryybig",
+ "mwe-timedtext-textcat-cue": "Cue-Pinkt",
+ "mwe-timedtext-no-subs": "Untertitel sin nit verfiegbar",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 Untertitel gfunde fir dr Videoclip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Kei $1 Untertitel gfunde fir dr Videoclip: $2",
+ "mwe-timedtext-upload-timed-text": "Untertitel uffelade"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json
new file mode 100644
index 00000000..5137aa27
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Guycn2",
+ "YaronSh"
+ ]
+ },
+ "mwe-timedtext-back-btn": "חזרה",
+ "mwe-timedtext-layout-off": "הסתרת כתוביות",
+ "mwe-timedtext-loading-text": "טעינת טקסט...",
+ "mwe-timedtext-textcat-cc": "כותרות",
+ "mwe-timedtext-textcat-sub": "כתוביות",
+ "mwe-timedtext-textcat-tad": "תיאור השמע",
+ "mwe-timedtext-textcat-ktv": "קראוקה",
+ "mwe-timedtext-textcat-tik": "שפת השורה הרצה",
+ "mwe-timedtext-textcat-ar": "אזורים פעילים",
+ "mwe-timedtext-textcat-nb": "פרשנות",
+ "mwe-timedtext-textcat-meta": "מטא־מתונים מתוזמנים",
+ "mwe-timedtext-textcat-trx": "תמליל",
+ "mwe-timedtext-textcat-lrc": "מילות השיר",
+ "mwe-timedtext-textcat-lin": "סימון בלשני",
+ "mwe-timedtext-textcat-cue": "נקודות סימנית",
+ "mwe-timedtext-no-subs": "אין רצועת תמליל זמינה",
+ "mwe-timedtext-language-subtitles-for-clip": "כתוביות ב{{grammar:תחילית|$1}} עבור הסרטון $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "לא נמצאו כתוביות ב{{grammar:תחילית|$1}} עבור $2",
+ "mwe-timedtext-upload-timed-text": "הוספת כתוביות"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json
new file mode 100644
index 00000000..325044d8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Wróćo",
+ "mwe-timedtext-layout-off": "Podtitule schować",
+ "mwe-timedtext-loading-text": "Tekst so začituje...",
+ "mwe-timedtext-textcat-cc": "Nadpisma",
+ "mwe-timedtext-textcat-sub": "Podtitule",
+ "mwe-timedtext-textcat-tad": "Awdiowopisanje",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Tekstowy běžacy pask",
+ "mwe-timedtext-textcat-ar": "Aktiwne regiony",
+ "mwe-timedtext-textcat-nb": "Anotacija",
+ "mwe-timedtext-textcat-meta": "Synchronizowane metadaty",
+ "mwe-timedtext-textcat-trx": "Přepis",
+ "mwe-timedtext-textcat-lrc": "Spěwowy tekst",
+ "mwe-timedtext-textcat-lin": "Rěčespytne wopisanje",
+ "mwe-timedtext-textcat-cue": "Zastupne dypki",
+ "mwe-timedtext-no-subs": "Žane podtitule k dispoziciji",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 {{PLURAL:$1|podtitul|podtitulej|podtitule|podtitulow}} za klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Žane podtitule $1 za klip namakane: $2",
+ "mwe-timedtext-upload-timed-text": "Podtitule přidać"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json
new file mode 100644
index 00000000..a5eb9692
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dani",
+ "Glanthor Reviol",
+ "Misibacsi"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Vissza",
+ "mwe-timedtext-layout-off": "Feliratok elrejtése",
+ "mwe-timedtext-loading-text": "Szöveg betöltése…",
+ "mwe-timedtext-textcat-cc": "Feliratok",
+ "mwe-timedtext-textcat-sub": "Felirat",
+ "mwe-timedtext-textcat-tad": "Hang leírása",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-ar": "Aktív régiók",
+ "mwe-timedtext-textcat-nb": "Annotáció",
+ "mwe-timedtext-textcat-meta": "Időzített metaadatok",
+ "mwe-timedtext-textcat-trx": "Átirat",
+ "mwe-timedtext-textcat-lrc": "Dalszöveg",
+ "mwe-timedtext-textcat-lin": "Nyelvi jelölés",
+ "mwe-timedtext-upload-timed-text": "Felirat hozzáadása"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json
new file mode 100644
index 00000000..624dc45d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Retornar",
+ "mwe-timedtext-layout-off": "Celar subtitulos",
+ "mwe-timedtext-loading-text": "Carga texto…",
+ "mwe-timedtext-textcat-cc": "Subtitulos",
+ "mwe-timedtext-textcat-sub": "Subtitulos",
+ "mwe-timedtext-textcat-tad": "Description audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Barra de information",
+ "mwe-timedtext-textcat-ar": "Regiones active",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "Metadatos de synchronisation",
+ "mwe-timedtext-textcat-trx": "Transcription",
+ "mwe-timedtext-textcat-lrc": "Lyricos",
+ "mwe-timedtext-textcat-lin": "Marcation lingusitic",
+ "mwe-timedtext-textcat-cue": "Punctos de entrata",
+ "mwe-timedtext-no-subs": "Subtitulos non disponibile",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtitulos in $1 pro le clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nulle subtitulos in $1 ha essite trovate pro le clip: $2",
+ "mwe-timedtext-upload-timed-text": "Adder subtitulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json
new file mode 100644
index 00000000..12a35bd7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Farras",
+ "IvanLanin"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Kembali",
+ "mwe-timedtext-layout-off": "Sembunyikan subjudul",
+ "mwe-timedtext-loading-text": "Memuat teks ...",
+ "mwe-timedtext-textcat-cc": "Keterangan",
+ "mwe-timedtext-textcat-sub": "Subjudul",
+ "mwe-timedtext-textcat-tad": "Deskripsi audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Teks tik",
+ "mwe-timedtext-textcat-ar": "Wilayah aktif",
+ "mwe-timedtext-textcat-nb": "Anotasi",
+ "mwe-timedtext-textcat-meta": "Data meta berjangka waktu",
+ "mwe-timedtext-textcat-trx": "Transkrip",
+ "mwe-timedtext-textcat-lrc": "Lirik",
+ "mwe-timedtext-textcat-lin": "Ubahan linguistik",
+ "mwe-timedtext-textcat-cue": "Titik acuan",
+ "mwe-timedtext-no-subs": "Jalur teks tidak tersedia",
+ "mwe-timedtext-language-subtitles-for-clip": "Subjudul $1 untuk klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Tidak ada subjudul $1 yang ditemukan untuk klip: $2",
+ "mwe-timedtext-upload-timed-text": "Unggah teks film"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json
new file mode 100644
index 00000000..4e2fad3a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Darth Kule",
+ "F. Cosoleto",
+ "Gianfranco"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Indietro",
+ "mwe-timedtext-layout-off": "Nascondi sottotitoli",
+ "mwe-timedtext-loading-text": "Caricamento testo...",
+ "mwe-timedtext-textcat-cc": "Didascalie",
+ "mwe-timedtext-textcat-sub": "Sottotitoli",
+ "mwe-timedtext-textcat-tad": "Descrizione audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Testo in movimento",
+ "mwe-timedtext-textcat-ar": "Regioni attive",
+ "mwe-timedtext-textcat-nb": "Annotazione",
+ "mwe-timedtext-textcat-meta": "Metadati temporizzati",
+ "mwe-timedtext-textcat-trx": "Trascrizione",
+ "mwe-timedtext-textcat-lrc": "Testi",
+ "mwe-timedtext-textcat-lin": "Markup linguistico",
+ "mwe-timedtext-textcat-cue": "Punti d'entrata",
+ "mwe-timedtext-no-subs": "Nessuna traccia di testo disponibile",
+ "mwe-timedtext-language-subtitles-for-clip": "sottotitoli in $1 per il filmato: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Sottotitoli in $1 non trovati per il filmato: $2",
+ "mwe-timedtext-upload-timed-text": "Aggiungi sottotitoli"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json
new file mode 100644
index 00000000..7e048693
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aotake",
+ "Hosiryuhosi",
+ "Shirayuki",
+ "Yanajin66",
+ "青子守歌"
+ ]
+ },
+ "mwe-timedtext-back-btn": "戻る",
+ "mwe-timedtext-layout-off": "字幕を隠す",
+ "mwe-timedtext-loading-text": "テキストの読み込み中...",
+ "mwe-timedtext-textcat-cc": "見出し",
+ "mwe-timedtext-textcat-sub": "字幕",
+ "mwe-timedtext-textcat-tad": "音声の説明",
+ "mwe-timedtext-textcat-ktv": "カラオケ",
+ "mwe-timedtext-textcat-tik": "ティッカー文章",
+ "mwe-timedtext-textcat-ar": "アクティブな領域",
+ "mwe-timedtext-textcat-nb": "注釈",
+ "mwe-timedtext-textcat-meta": "時間メタデータ",
+ "mwe-timedtext-textcat-trx": "複写",
+ "mwe-timedtext-textcat-lrc": "歌詞",
+ "mwe-timedtext-textcat-lin": "言語マーク",
+ "mwe-timedtext-textcat-cue": "キューポイント",
+ "mwe-timedtext-language-subtitles-for-clip": "クリップ $2 の$1字幕",
+ "mwe-timedtext-language-no-subtitles-for-clip": "クリップ $2 には$1字幕がありません",
+ "mwe-timedtext-upload-timed-text": "字幕を追加"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json
new file mode 100644
index 00000000..05eb95f5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010"
+ ]
+ },
+ "mwe-timedtext-back-btn": "უკან",
+ "mwe-timedtext-layout-off": "სუბტიტრების დამალვა",
+ "mwe-timedtext-loading-text": "იტვირთება ტექსტი ...",
+ "mwe-timedtext-textcat-cc": "წარწერები",
+ "mwe-timedtext-textcat-sub": "სუბტიტრები",
+ "mwe-timedtext-textcat-tad": "აუდიო აღწერა",
+ "mwe-timedtext-textcat-ktv": "კარაოკე",
+ "mwe-timedtext-textcat-tik": "ტექსტური ბარათები",
+ "mwe-timedtext-textcat-ar": "აქტიური რეგიონები",
+ "mwe-timedtext-textcat-nb": "ანოტაცია",
+ "mwe-timedtext-textcat-meta": "სინქრონიზირებული მეტამონაცემები",
+ "mwe-timedtext-textcat-trx": "სტენოგრამა",
+ "mwe-timedtext-textcat-lrc": "სიმღერის ტექსტები",
+ "mwe-timedtext-textcat-lin": "ლინგვისტური დანამატი",
+ "mwe-timedtext-textcat-cue": "ნიშნული წერტილები",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 სუბტიტრები კლიპისათვის: $2",
+ "mwe-timedtext-upload-timed-text": "სუბტიტრების დამატება"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json
new file mode 100644
index 00000000..9b4faaf5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "아라"
+ ]
+ },
+ "mwe-timedtext-back-btn": "뒤로",
+ "mwe-timedtext-layout-off": "자막 숨기기",
+ "mwe-timedtext-loading-text": "텍스트 불러오는 중 ...",
+ "mwe-timedtext-textcat-cc": "설명",
+ "mwe-timedtext-textcat-sub": "자막",
+ "mwe-timedtext-textcat-tad": "소리 설명",
+ "mwe-timedtext-textcat-ktv": "가라오케",
+ "mwe-timedtext-textcat-tik": "표시기 문자",
+ "mwe-timedtext-textcat-ar": "활성 영역",
+ "mwe-timedtext-textcat-nb": "주석",
+ "mwe-timedtext-textcat-meta": "시간 메타데이터",
+ "mwe-timedtext-textcat-trx": "복사",
+ "mwe-timedtext-textcat-lrc": "가사",
+ "mwe-timedtext-textcat-lin": "언어 마크업",
+ "mwe-timedtext-textcat-cue": "큐 포인트",
+ "mwe-timedtext-no-subs": "사용할 수 있는 텍스트 트랙이 없습니다",
+ "mwe-timedtext-language-subtitles-for-clip": "클립에 대한 $1 자막: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "클립에 대한 $1 자막을 찾을 수 없습니다: $2",
+ "mwe-timedtext-upload-timed-text": "자막 추가"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json
new file mode 100644
index 00000000..13036810
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "mwe-timedtext-language-no-subtitles-for-clip": "Mer han kei $1 Ongertittelle jefonge för dat Shtöck: $2"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json
new file mode 100644
index 00000000..ad8d40e7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby",
+ "Soued031"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zréck",
+ "mwe-timedtext-layout-off": "Ënnertitele verstoppen",
+ "mwe-timedtext-loading-text": "Text gëtt gelueden ...",
+ "mwe-timedtext-textcat-sub": "Ënnertitelen",
+ "mwe-timedtext-textcat-tad": "Audio-Beschreiwung",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text-Ticker",
+ "mwe-timedtext-textcat-ar": "Aktiv Regiounen",
+ "mwe-timedtext-textcat-nb": "Notiz",
+ "mwe-timedtext-textcat-lrc": "Liddertext",
+ "mwe-timedtext-textcat-lin": "Linguistesch Markéierung",
+ "mwe-timedtext-textcat-cue": "Referenz-Punkten",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 Ënnertitele fir de Clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Keng $1 Ënnertitele goufe fonnt fir de Clip: $2",
+ "mwe-timedtext-upload-timed-text": "Ënnertitelen derbäisetzen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json
new file mode 100644
index 00000000..af653701
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg"
+ ]
+ },
+ "mwe-timedtext-no-subs": "Nėra tekstinių takelių",
+ "mwe-timedtext-upload-timed-text": "Pridėti subtitrus"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json
new file mode 100644
index 00000000..55f99f5a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Papuass"
+ ]
+ },
+ "mwe-timedtext-textcat-nb": "Anotācija",
+ "mwe-timedtext-textcat-trx": "Transkripts"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json
new file mode 100644
index 00000000..1dd29c01
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Скриј титлови",
+ "mwe-timedtext-loading-text": "Го вчитувам текстот...",
+ "mwe-timedtext-textcat-cc": "Опис",
+ "mwe-timedtext-textcat-sub": "Титлови",
+ "mwe-timedtext-textcat-tad": "Аудио-опис",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Текст-картички",
+ "mwe-timedtext-textcat-ar": "Активни региони",
+ "mwe-timedtext-textcat-nb": "Прибелешка",
+ "mwe-timedtext-textcat-meta": "Синхронизирани метаподатоци",
+ "mwe-timedtext-textcat-trx": "Стенограм",
+ "mwe-timedtext-textcat-lrc": "Текст на песната",
+ "mwe-timedtext-textcat-lin": "Лингвистичко означување",
+ "mwe-timedtext-textcat-cue": "Моментни точки",
+ "mwe-timedtext-no-subs": "Нема титлови на располагање",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 — титлови за снимката: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Нема пронајдено титлови на $1 за снимката: $2",
+ "mwe-timedtext-upload-timed-text": "Стави титлови"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json
new file mode 100644
index 00000000..a8d34824
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Praveenp"
+ ]
+ },
+ "mwe-timedtext-back-btn": "പുറകോട്ട്",
+ "mwe-timedtext-layout-off": "സംഭാഷണരേഖ മറയ്ക്കുക",
+ "mwe-timedtext-loading-text": "എഴുത്ത് ശേഖരിക്കുന്നു...",
+ "mwe-timedtext-textcat-cc": "തലവാക്യം",
+ "mwe-timedtext-textcat-sub": "സംഭാഷണരേഖകൾ",
+ "mwe-timedtext-textcat-tad": "ശബ്ദത്തിന്റെ വിവരണം",
+ "mwe-timedtext-textcat-ktv": "കരോക്കേ",
+ "mwe-timedtext-textcat-tik": "മിന്നിവരുന്ന എഴുത്ത്",
+ "mwe-timedtext-textcat-ar": "സജീവമായ പ്രദേശങ്ങൾ",
+ "mwe-timedtext-textcat-nb": "ടിപ്പണി",
+ "mwe-timedtext-textcat-meta": "സമയമനുസരിച്ചുള്ള മെറ്റാഡേറ്റ",
+ "mwe-timedtext-textcat-trx": "പകർത്തിയെഴുത്ത്",
+ "mwe-timedtext-textcat-lrc": "വരികൾ",
+ "mwe-timedtext-textcat-lin": "ഭാഷാസംബന്ധിയായ അടയാളഭാഷ",
+ "mwe-timedtext-textcat-cue": "സൂചക ബിന്ദുക്കൾ",
+ "mwe-timedtext-no-subs": "എഴുത്തുകളുടെ വരി ലഭ്യമല്ല",
+ "mwe-timedtext-language-subtitles-for-clip": "ഈ മീഡിയശകലത്തിന് $1 ഭാഷയിലുള്ള സംഭാഷണരേഖ: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "ഈ മീഡിയശകലത്തിന് $1 ഭാഷയിലുള്ള സംഭാഷണരേഖയൊന്നും കണ്ടെത്താനായില്ല: $2",
+ "mwe-timedtext-upload-timed-text": "സംഭാഷണരേഖ കൂട്ടിച്ചേർക്കുക"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json
new file mode 100644
index 00000000..712fff27
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Kembali",
+ "mwe-timedtext-layout-off": "Sorokkan sari kata",
+ "mwe-timedtext-loading-text": "Teks sedang dimuatkan...",
+ "mwe-timedtext-textcat-cc": "Kapsyen",
+ "mwe-timedtext-textcat-sub": "Sari kata",
+ "mwe-timedtext-textcat-tad": "Keterangan audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Teks ticker",
+ "mwe-timedtext-textcat-ar": "Kawasan aktif",
+ "mwe-timedtext-textcat-nb": "Anotasi",
+ "mwe-timedtext-textcat-meta": "Metadata bermasa",
+ "mwe-timedtext-textcat-trx": "Transkrip",
+ "mwe-timedtext-textcat-lrc": "Lirik",
+ "mwe-timedtext-textcat-lin": "Penanda linguistik",
+ "mwe-timedtext-textcat-cue": "Titik kiu",
+ "mwe-timedtext-no-subs": "Tidak terdapat runut teks",
+ "mwe-timedtext-language-subtitles-for-clip": "Sari kata $1 untuk klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Tidak terdapat sari kata $1 untuk klip: $2",
+ "mwe-timedtext-upload-timed-text": "Letak sari kata"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json
new file mode 100644
index 00000000..a273d46b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danmichaelo",
+ "Nghtwlkr"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Tilbake",
+ "mwe-timedtext-layout-off": "Gjem undertekster",
+ "mwe-timedtext-loading-text": "Laster tekst ...",
+ "mwe-timedtext-textcat-cc": "Undertektster",
+ "mwe-timedtext-textcat-sub": "Undertekster",
+ "mwe-timedtext-textcat-tad": "Lydbeskrivelse",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Tekst-ticker",
+ "mwe-timedtext-textcat-ar": "Aktive regioner",
+ "mwe-timedtext-textcat-nb": "Merknad",
+ "mwe-timedtext-textcat-meta": "Tidsbestemt metadata",
+ "mwe-timedtext-textcat-trx": "Transkripsjon",
+ "mwe-timedtext-textcat-lrc": "Tekster",
+ "mwe-timedtext-no-subs": "Ingen tekstspor finnes",
+ "mwe-timedtext-language-subtitles-for-clip": "Undertekster på $1 for klippet: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Ingen undertekster på $1 ble funnet for klippet: $2",
+ "mwe-timedtext-upload-timed-text": "Legg til undertekster"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json
new file mode 100644
index 00000000..7b225402
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Siebrand"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Terug",
+ "mwe-timedtext-layout-off": "Ondertitels verbergen",
+ "mwe-timedtext-loading-text": "Bezig met het laden van de tekst...",
+ "mwe-timedtext-textcat-cc": "Ondertitels",
+ "mwe-timedtext-textcat-sub": "Ondertitels",
+ "mwe-timedtext-textcat-tad": "Audiobeschrijving",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Informatiebalk",
+ "mwe-timedtext-textcat-ar": "Actieve gebieden",
+ "mwe-timedtext-textcat-nb": "Annotatie",
+ "mwe-timedtext-textcat-meta": "Tijdgebaseerde metadata",
+ "mwe-timedtext-textcat-trx": "Transcriptie",
+ "mwe-timedtext-textcat-lrc": "Songteksten",
+ "mwe-timedtext-textcat-lin": "Taalkundige markup",
+ "mwe-timedtext-textcat-cue": "Richtpunten",
+ "mwe-timedtext-no-subs": "Er zijn geen teksttracks beschikbaar",
+ "mwe-timedtext-language-subtitles-for-clip": "Ondertitels in het $1 voor clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Er zijn geen ondertitels in de taal $1 gevonden voor clip: $2",
+ "mwe-timedtext-upload-timed-text": "Ondertitels toevoegen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json
new file mode 100644
index 00000000..696c63d4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Njardarlogar"
+ ]
+ },
+ "mwe-timedtext-layout-off": "Gøym undertekstar",
+ "mwe-timedtext-textcat-sub": "Undertekstar",
+ "mwe-timedtext-textcat-lrc": "Tekstar",
+ "mwe-timedtext-no-subs": "Ingen tekstspor er tilgjengelege",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 undertekstar for klippet: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Ingen undertekster på $1 vart funne for klippet: $2",
+ "mwe-timedtext-upload-timed-text": "Legg til undertekstar"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json
new file mode 100644
index 00000000..56c9fe84
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xqt"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zerrick"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json
new file mode 100644
index 00000000..2e41e363
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Manuae"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json
new file mode 100644
index 00000000..544812d0
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "BeginaFelicysym",
+ "Leinad",
+ "Shadown",
+ "Sp5uhe"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Wstecz",
+ "mwe-timedtext-layout-off": "Ukryj napisy",
+ "mwe-timedtext-loading-text": "Ładowanie tekstu...",
+ "mwe-timedtext-textcat-cc": "Podpisy",
+ "mwe-timedtext-textcat-sub": "Napisy do filmu",
+ "mwe-timedtext-textcat-tad": "Opis ścieżki dźwiękowej",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Notatka",
+ "mwe-timedtext-textcat-ar": "Aktywne regiony",
+ "mwe-timedtext-textcat-nb": "Adnotacja",
+ "mwe-timedtext-textcat-meta": "Metadane ze znacznikami czasu",
+ "mwe-timedtext-textcat-trx": "Rozpisz",
+ "mwe-timedtext-textcat-lrc": "Teksty piosenek",
+ "mwe-timedtext-textcat-lin": "Znaczniki językowe",
+ "mwe-timedtext-textcat-cue": "Punkty kontrolne",
+ "mwe-timedtext-no-subs": "Nie ma dostępnych ścieżek tekstowych",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 napisy do filmu: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nie odnaleziono $1 napisów do filmu: $2",
+ "mwe-timedtext-upload-timed-text": "Dodaj napisy"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json
new file mode 100644
index 00000000..7ffca36c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt"
+ ]
+ },
+ "mwe-timedtext-back-btn": "André",
+ "mwe-timedtext-layout-off": "Stërmé ij sot-tìtoj",
+ "mwe-timedtext-loading-text": "Cariament dël test...",
+ "mwe-timedtext-textcat-cc": "Descrission",
+ "mwe-timedtext-textcat-sub": "Sot-tìtoj",
+ "mwe-timedtext-textcat-tad": "Descrission àudio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Test ëd la telescrivent",
+ "mwe-timedtext-textcat-ar": "Region ative",
+ "mwe-timedtext-textcat-nb": "Nòta",
+ "mwe-timedtext-textcat-meta": "Metadat sincronisà",
+ "mwe-timedtext-textcat-trx": "Trascrission",
+ "mwe-timedtext-textcat-lrc": "Lìriche",
+ "mwe-timedtext-textcat-lin": "Marcador lenghìstich",
+ "mwe-timedtext-textcat-cue": "Pont d'arferiment",
+ "mwe-timedtext-no-subs": "Gnun-e marche ëd test disponìbij",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 sot-tìtoj për ël tòch: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "A l'é trovasse gnun sot-tìtoj $1 per ël tòch: $2",
+ "mwe-timedtext-upload-timed-text": "Gionté dij sot-tìtoj"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json
new file mode 100644
index 00000000..fd556365
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "mwe-timedtext-textcat-ktv": "کارااوکه"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json
new file mode 100644
index 00000000..008c55ba
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dianakc",
+ "Giro720",
+ "Luckas",
+ "Luckas Blade",
+ "555"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Voltar",
+ "mwe-timedtext-layout-off": "Ocultar legendas",
+ "mwe-timedtext-loading-text": "Carregando o texto ...",
+ "mwe-timedtext-textcat-cc": "Títulos",
+ "mwe-timedtext-textcat-sub": "Legendas",
+ "mwe-timedtext-textcat-tad": "Descrição do áudio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Texto deslizante",
+ "mwe-timedtext-textcat-ar": "Regiões ativas",
+ "mwe-timedtext-textcat-nb": "Anotação",
+ "mwe-timedtext-textcat-meta": "Metadados sincronizados",
+ "mwe-timedtext-textcat-trx": "Transcrição",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Marcação linguística",
+ "mwe-timedtext-textcat-cue": "Pontos de entrada",
+ "mwe-timedtext-no-subs": "Não há nenhum texto disponível",
+ "mwe-timedtext-language-subtitles-for-clip": "Legendas em $1 para o clipe: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Não foram encontradas legendas em $1 para o clipe: $2",
+ "mwe-timedtext-upload-timed-text": "Adicionar legendas"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json
new file mode 100644
index 00000000..4917da79
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Giro720",
+ "Hamilton Abreu",
+ "Luckas",
+ "SandroHc",
+ "Vitorvicentevalente"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Voltar",
+ "mwe-timedtext-layout-off": "Ocultar legendas",
+ "mwe-timedtext-loading-text": "A carregar o texto ...",
+ "mwe-timedtext-textcat-cc": "Títulos",
+ "mwe-timedtext-textcat-sub": "Legendas",
+ "mwe-timedtext-textcat-tad": "Descrição de áudio",
+ "mwe-timedtext-textcat-ktv": "Caraoque",
+ "mwe-timedtext-textcat-tik": "Cotações",
+ "mwe-timedtext-textcat-ar": "Regiões activas",
+ "mwe-timedtext-textcat-nb": "Anotação",
+ "mwe-timedtext-textcat-meta": "Metadados de sincronização",
+ "mwe-timedtext-textcat-trx": "Transcrição",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Marcação linguística",
+ "mwe-timedtext-textcat-cue": "Pontos de entrada",
+ "mwe-timedtext-no-subs": "Não há nenhuma faixa de texto disponível",
+ "mwe-timedtext-language-subtitles-for-clip": "Legendas em $1 para o clipe: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Não foram encontradas legendas em $1 para o clipe: $2",
+ "mwe-timedtext-upload-timed-text": "Adicionar legendas"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json
new file mode 100644
index 00000000..4714d5b1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Shirayuki",
+ "Siebrand",
+ "Umherirrender"
+ ]
+ },
+ "mwe-timedtext-back-btn": "{{Identical|Back}}",
+ "mwe-timedtext-key-language": "{{optional}}\nParameters:\n* $1 - language key. e.g. \"en\"\n* $2 - language name",
+ "mwe-timedtext-textcat-cc": "{{Identical|Caption}}",
+ "mwe-timedtext-textcat-sub": "{{Identical|Subtitle}}",
+ "mwe-timedtext-textcat-ktv": "See [[w:Karaoke]].",
+ "mwe-timedtext-textcat-nb": "{{Identical|Annotation}}",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 is language name for subtitles (e.g. \"English\"), $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page exists. See also mwe-timedtext-language-no-subtitles-for-clip.",
+ "mwe-timedtext-language-no-subtitles-for-clip": "$1 is language name, $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page does not exist. See also mwe-timedtext-language-subtitles-for-clip",
+ "mwe-timedtext-upload-timed-text": "After clicking the 'CC' button on the video player, the button on the resulting menu to add subtitles to a video file."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json
new file mode 100644
index 00000000..77892ab4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minisarm",
+ "Stelistcristi"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Înapoi",
+ "mwe-timedtext-layout-off": "Ascunde subtitrările",
+ "mwe-timedtext-loading-text": "Se încarcă textul...",
+ "mwe-timedtext-textcat-cc": "Legende",
+ "mwe-timedtext-textcat-sub": "Subtitrări",
+ "mwe-timedtext-textcat-tad": "Descriere audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text mai gros",
+ "mwe-timedtext-textcat-ar": "Regiuni active",
+ "mwe-timedtext-textcat-nb": "Adnotare",
+ "mwe-timedtext-textcat-meta": "Metadate sincronizate",
+ "mwe-timedtext-textcat-trx": "Transcripție",
+ "mwe-timedtext-textcat-lrc": "Versuri",
+ "mwe-timedtext-textcat-lin": "Etichete lingvistice",
+ "mwe-timedtext-textcat-cue": "Puncte de tac",
+ "mwe-timedtext-no-subs": "Niciun text de piesă disponibil",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtitrare în limba $1 pentru clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nu s-a găsit nicio subtitrare în limba $1 pentru clip: $2",
+ "mwe-timedtext-upload-timed-text": "Adaugă subtitrări"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json
new file mode 100644
index 00000000..a26678a4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Rrete",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-nb": "Annotazione",
+ "mwe-timedtext-textcat-meta": "Metadate temborizzate",
+ "mwe-timedtext-textcat-trx": "Trascrive",
+ "mwe-timedtext-textcat-lrc": "Teste",
+ "mwe-timedtext-upload-timed-text": "Aggiunge le sottotitole"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json
new file mode 100644
index 00000000..8b3ff81c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "MaxSem",
+ "Okras",
+ "Александр Сигачёв",
+ "Kaganer"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Скрыть субтитры",
+ "mwe-timedtext-loading-text": "Загрузка текста…",
+ "mwe-timedtext-textcat-cc": "Субтитры-описания",
+ "mwe-timedtext-textcat-sub": "Субтитры",
+ "mwe-timedtext-textcat-tad": "Описание аудиофайла",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Текстовые карточки",
+ "mwe-timedtext-textcat-ar": "Активные области",
+ "mwe-timedtext-textcat-nb": "Аннотация",
+ "mwe-timedtext-textcat-meta": "Синхронизированные метаданные",
+ "mwe-timedtext-textcat-trx": "Стенограмма",
+ "mwe-timedtext-textcat-lrc": "Слова песни",
+ "mwe-timedtext-textcat-lin": "Лингвистическая разметка",
+ "mwe-timedtext-textcat-cue": "Знаковые точки",
+ "mwe-timedtext-no-subs": "Нет текстовых дорожек",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 — субтитры для клипа: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Не найдено субтитров на $1 для клипа: $2",
+ "mwe-timedtext-upload-timed-text": "Добавить субтитры"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json
new file mode 100644
index 00000000..1cc92d6f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazeb"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json
new file mode 100644
index 00000000..8af0327f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "ආපසු",
+ "mwe-timedtext-layout-off": "උපශීර්ෂ සඟවන්න",
+ "mwe-timedtext-loading-text": "පෙළ පූරණය වෙමින් ...",
+ "mwe-timedtext-textcat-cc": "උපන්‍යාස",
+ "mwe-timedtext-textcat-sub": "උපශීර්ෂ",
+ "mwe-timedtext-textcat-tad": "ශ්‍රව්‍ය විස්තරය",
+ "mwe-timedtext-textcat-ktv": "කැරෝකේ",
+ "mwe-timedtext-textcat-tik": "ඔරලෝසු පෙළ",
+ "mwe-timedtext-textcat-ar": "සක්‍රිය ප්‍රදේශ",
+ "mwe-timedtext-textcat-nb": "ටීකාව",
+ "mwe-timedtext-textcat-meta": "කාලිත පාරදත්ත",
+ "mwe-timedtext-textcat-trx": "ප්‍රතිලේඛනය",
+ "mwe-timedtext-textcat-lrc": "ගීපදවැල්",
+ "mwe-timedtext-textcat-lin": "භාෂාමය අධිකය",
+ "mwe-timedtext-textcat-cue": "ඉංගිත ගතිගුණ",
+ "mwe-timedtext-no-subs": "මීළඟ පථ ලබාගත නොහැක",
+ "mwe-timedtext-language-subtitles-for-clip": "ක්ලිපය සඳහා $1 උපසිරුස: $2",
+ "mwe-timedtext-upload-timed-text": "උපශීර්ෂ එක් කරන්න"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json
new file mode 100644
index 00000000..8df43558
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dbc334"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Nazaj"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json
new file mode 100644
index 00000000..6a979a8b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Abshirdheere"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json
new file mode 100644
index 00000000..f3dfbbc6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rancher",
+ "Михајло Анђелковић"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Сакриј сабтајтлове",
+ "mwe-timedtext-loading-text": "Учитава се текст ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Ознаке",
+ "mwe-timedtext-textcat-sub": "Поднаслови",
+ "mwe-timedtext-textcat-trx": "Транскрипт"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json
new file mode 100644
index 00000000..100a6fc3
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rancher"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Nazad",
+ "mwe-timedtext-layout-off": "Sakrij sabtajtlove",
+ "mwe-timedtext-loading-text": "Učitava se tekst ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Oznake",
+ "mwe-timedtext-textcat-sub": "Podnaslovi",
+ "mwe-timedtext-textcat-trx": "Transkript"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json
new file mode 100644
index 00000000..a0b693cd
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ainali",
+ "Dafer45"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Tillbaka",
+ "mwe-timedtext-layout-off": "Dölj undertexter",
+ "mwe-timedtext-loading-text": "Laddar text ...",
+ "mwe-timedtext-textcat-cc": "Undertexter",
+ "mwe-timedtext-textcat-sub": "Undertexter",
+ "mwe-timedtext-textcat-tad": "Ljudbeskrivning",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Rullande text",
+ "mwe-timedtext-textcat-ar": "Aktiva regioner",
+ "mwe-timedtext-textcat-nb": "Anmärkning",
+ "mwe-timedtext-textcat-meta": "Tidsbestämd metadata",
+ "mwe-timedtext-textcat-trx": "Transkription",
+ "mwe-timedtext-textcat-lrc": "Texter",
+ "mwe-timedtext-textcat-lin": "Språkliga markeringar",
+ "mwe-timedtext-textcat-cue": "Referenspunkter",
+ "mwe-timedtext-no-subs": "Inga textspår finns",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 undertexter för klipp: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Inga $1 undertexter hittades för klipp: $2",
+ "mwe-timedtext-upload-timed-text": "Lägga till undertexter"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json
new file mode 100644
index 00000000..6e9ef3e8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Karthi.dr",
+ "Shanmugamp7",
+ "மதனாஹரன்"
+ ]
+ },
+ "mwe-timedtext-back-btn": "பின்செல்",
+ "mwe-timedtext-layout-off": "துணைத்தலைப்புக்களை மறை",
+ "mwe-timedtext-loading-text": "உரையை ஏற்றுகிறது ...",
+ "mwe-timedtext-textcat-sub": "துணைத்தலைப்புக்கள்",
+ "mwe-timedtext-textcat-tad": "ஒலித விவரணம்",
+ "mwe-timedtext-textcat-lrc": "பாடல் வரிகள்",
+ "mwe-timedtext-upload-timed-text": "துணைத்தலைப்புக்களைச் சேர்"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json
new file mode 100644
index 00000000..50688138
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Veeven"
+ ]
+ },
+ "mwe-timedtext-back-btn": "వెనక్కి",
+ "mwe-timedtext-textcat-sub": "ఉపశీర్షికలు"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json
new file mode 100644
index 00000000..971a8f30
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Bumalik",
+ "mwe-timedtext-layout-off": "Itago ang kabahaging mga pamagat",
+ "mwe-timedtext-loading-text": "Ikinakarga ang teksto ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Mga paliwanag",
+ "mwe-timedtext-textcat-sub": "Kabahaging mga pamagat",
+ "mwe-timedtext-textcat-tad": "Paglalarawan ng naririnig",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Teksto ng pampulso",
+ "mwe-timedtext-textcat-ar": "Masisiglang mga rehiyon",
+ "mwe-timedtext-textcat-nb": "Paliwanag",
+ "mwe-timedtext-textcat-meta": "Inorasang metadato",
+ "mwe-timedtext-textcat-trx": "Sipi ng salin",
+ "mwe-timedtext-textcat-lrc": "Titik ng awit",
+ "mwe-timedtext-textcat-lin": "Markang-pantaas ng lingguwistika",
+ "mwe-timedtext-textcat-cue": "Mga tuldok ng pahiwatig",
+ "mwe-timedtext-no-subs": "Walang makukuhang mga bakas ng teksto",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 kabahaging mga pamagat para sa putol na: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Walang natagpuang $1 kabahaging mga pamagat para sa putol na: $2",
+ "mwe-timedtext-upload-timed-text": "Magdagdag ng kabahaging mga pamagat"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json
new file mode 100644
index 00000000..8b26730a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Emperyan"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Geri",
+ "mwe-timedtext-textcat-sub": "Alt yazılar",
+ "mwe-timedtext-no-subs": "Parça metni yok",
+ "mwe-timedtext-upload-timed-text": "Alt yazı ekle"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json
new file mode 100644
index 00000000..916f0395
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Base",
+ "Тест"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Приховати субтитри",
+ "mwe-timedtext-loading-text": "Завантаження тексту…",
+ "mwe-timedtext-textcat-cc": "Субтитри-підписи",
+ "mwe-timedtext-textcat-sub": "Субтитри",
+ "mwe-timedtext-textcat-tad": "Аудіо-опис",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Текстові картки",
+ "mwe-timedtext-textcat-ar": "Активні області",
+ "mwe-timedtext-textcat-nb": "Анотація",
+ "mwe-timedtext-textcat-meta": "Синхронізовані метадані",
+ "mwe-timedtext-textcat-trx": "Стенограма",
+ "mwe-timedtext-textcat-lrc": "Слова пісні",
+ "mwe-timedtext-textcat-lin": "Лінгвістична розмітка",
+ "mwe-timedtext-textcat-cue": "Знакові точки",
+ "mwe-timedtext-no-subs": "Немає текстових доріжок",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 — субтитри для кліпу: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Не знайдено субтитрів $1 для кліпу: $2",
+ "mwe-timedtext-upload-timed-text": "Додати субтитри"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json
new file mode 100644
index 00000000..baafae32
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "واپس",
+ "mwe-timedtext-textcat-sub": "رومانیہ"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json
new file mode 100644
index 00000000..5ee9bb9b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Quay lại",
+ "mwe-timedtext-layout-off": "Ẩn phụ đề",
+ "mwe-timedtext-loading-text": "Đang tải văn bản…",
+ "mwe-timedtext-textcat-sub": "Phụ đề",
+ "mwe-timedtext-textcat-tad": "Lời miêu tả âm thanh",
+ "mwe-timedtext-textcat-ktv": "Karaôkê",
+ "mwe-timedtext-textcat-meta": "Siêu dữ liệu đồng bộ",
+ "mwe-timedtext-textcat-lrc": "Lời hát",
+ "mwe-timedtext-textcat-lin": "Đánh dấu ngôn ngữ học",
+ "mwe-timedtext-upload-timed-text": "Thêm phụ đề"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json
new file mode 100644
index 00000000..c8d2fdf6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Srtxg"
+ ]
+ },
+ "mwe-timedtext-layout-off": "Catchî les dzo-tites",
+ "mwe-timedtext-loading-text": "Dji tchedje li tecse...",
+ "mwe-timedtext-textcat-cc": "Ledjindes",
+ "mwe-timedtext-textcat-sub": "Dizo-tites",
+ "mwe-timedtext-textcat-lrc": "Paroles",
+ "mwe-timedtext-textcat-lin": "Etiketes di lingaedje",
+ "mwe-timedtext-language-subtitles-for-clip": "Dizo-tites e $1 pol clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nou dzo-tite $1 di trové pol clip: $2"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json
new file mode 100644
index 00000000..c05e1576
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער"
+ ]
+ },
+ "mwe-timedtext-back-btn": "צוריק",
+ "mwe-timedtext-textcat-cc": "באשרייבונגען"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json
new file mode 100644
index 00000000..d13683e9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shizhao",
+ "Simon Shek",
+ "Wilsonmess",
+ "Xiaomingyan",
+ "Yfdyh000"
+ ]
+ },
+ "mwe-timedtext-back-btn": "返回",
+ "mwe-timedtext-layout-off": "隐藏字幕",
+ "mwe-timedtext-loading-text": "正在载入文本...",
+ "mwe-timedtext-textcat-cc": "说明",
+ "mwe-timedtext-textcat-sub": "副标题",
+ "mwe-timedtext-textcat-tad": "声音说明",
+ "mwe-timedtext-textcat-ktv": "卡拉OK",
+ "mwe-timedtext-textcat-tik": "滚动文本",
+ "mwe-timedtext-textcat-ar": "作用区域",
+ "mwe-timedtext-textcat-nb": "注释",
+ "mwe-timedtext-textcat-meta": "字幕元数据",
+ "mwe-timedtext-textcat-trx": "字幕",
+ "mwe-timedtext-textcat-lrc": "歌词",
+ "mwe-timedtext-textcat-lin": "语言标记",
+ "mwe-timedtext-textcat-cue": "提示点",
+ "mwe-timedtext-no-subs": "没有可用的字幕",
+ "mwe-timedtext-language-subtitles-for-clip": "片段$2的$1字幕",
+ "mwe-timedtext-language-no-subtitles-for-clip": "没有找到片段$2的$1字幕",
+ "mwe-timedtext-upload-timed-text": "添加字幕"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json
new file mode 100644
index 00000000..b653aeb1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Justincheng12345",
+ "Mark85296341",
+ "Simon Shek",
+ "LNDDYL"
+ ]
+ },
+ "mwe-timedtext-back-btn": "返回",
+ "mwe-timedtext-layout-off": "隱藏字幕",
+ "mwe-timedtext-loading-text": "正在讀取文字……",
+ "mwe-timedtext-textcat-cc": "標題",
+ "mwe-timedtext-textcat-sub": "副標題",
+ "mwe-timedtext-textcat-tad": "音訊說明",
+ "mwe-timedtext-textcat-ktv": "卡拉OK",
+ "mwe-timedtext-textcat-tik": "滾動文本",
+ "mwe-timedtext-textcat-ar": "有效區城",
+ "mwe-timedtext-textcat-nb": "註解",
+ "mwe-timedtext-textcat-meta": "字幕元資料",
+ "mwe-timedtext-textcat-trx": "字幕",
+ "mwe-timedtext-textcat-lrc": "歌詞",
+ "mwe-timedtext-textcat-lin": "語言標記",
+ "mwe-timedtext-textcat-cue": "暗點",
+ "mwe-timedtext-no-subs": "無可用字幕",
+ "mwe-timedtext-language-subtitles-for-clip": "片段的$1字幕文件:$2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "沒有找到片段的$1字幕文件:$2",
+ "mwe-timedtext-upload-timed-text": "添加字幕"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js
new file mode 100644
index 00000000..cce8310f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js
@@ -0,0 +1,504 @@
+/**
+ * Base mw.TextSource object
+ *
+ * @param {Object} source Source object to extend
+ * @param {Object} textProvider [Optional] The text provider interface ( to load source from api )
+ */
+( function( mw, $ ) { "use strict";
+
+ mw.TextSource = function( source ) {
+ return this.init( source );
+ };
+ mw.TextSource.prototype = {
+
+ //The load state:
+ loaded: false,
+
+ // Container for the captions
+ // captions include "start", "end" and "content" fields
+ captions: [],
+
+ // The css style for captions ( some file formats specify display types )
+ styleCss: {},
+
+ // The previous index of the timed text served
+ // Avoids searching the entire array on time updates.
+ prevIndex: 0,
+
+ /**
+ * @constructor Inherits mediaSource from embedPlayer
+ * @param {source} Base source element
+ * @param {Object} Pointer to the textProvider
+ */
+ init: function( source , textProvider) {
+ // Inherits mediaSource
+ for( var i in source){
+ this[ i ] = source[ i ];
+ }
+
+ // Set default category to subtitle if unset:
+ if( ! this.kind ) {
+ this.kind = 'subtitle';
+ }
+ //Set the textProvider if provided
+ if( textProvider ) {
+ this.textProvider = textProvider;
+ }
+ return this;
+ },
+
+ /**
+ * Function to load and parse the source text
+ * @param {Function} callback Function called once text source is loaded
+ */
+ load: function( callback ) {
+ var _this = this;
+ mw.log("TextSource:: load src "+ _this.getSrc() );
+
+ // Setup up a callback ( in case it was not defined )
+ if( !callback ){
+ callback = function(){ return ; };
+ }
+
+ // Check if the captions have already been loaded:
+ if( this.loaded ){
+ return callback();
+ }
+
+ // Try to load src via XHR source
+ if( !this.getSrc() ) {
+ mw.log( "Error: TextSource no source url for text track");
+ return callback();
+ }
+
+ // Check type for special loaders:
+ $( mw ).triggerQueueCallback( 'TimedText_LoadTextSource', _this, function(){
+ if( _this.loaded ){
+ callback();
+ } else {
+ // if no module loaded the text source use the normal ajax proxy:
+ new mw.ajaxProxy({
+ url: _this.getSrc(),
+ success: function( resultXML ) {
+ _this.captions = _this.getCaptions( resultXML );
+ _this.loaded = true;
+ mw.log("mw.TextSource :: loaded from " + _this.getSrc() + " Found: " + _this.captions.length + ' captions' );
+ callback();
+ },
+ error: function() {
+ mw.log("Error: TextSource Error with http response");
+ _this.loaded = true;
+ callback();
+ }
+ });
+ }
+ })
+ },
+ /**
+ * Returns the text content for requested time
+ *
+ * @param {Number} time Time in seconds
+ */
+ getCaptionForTime: function ( time ) {
+ var prevCaption = this.captions[ this.prevIndex ];
+ var captionSet = {};
+
+ // Setup the startIndex:
+ if( prevCaption && time >= prevCaption.start ) {
+ var startIndex = this.prevIndex;
+ }else{
+ // If a backwards seek start searching at the start:
+ var startIndex = 0;
+ }
+ var firstCapIndex = 0;
+ // Start looking for the text via time, add all matches that are in range
+ for( var i = startIndex ; i < this.captions.length; i++ ) {
+ var caption = this.captions[ i ];
+ // Don't handle captions with 0 or -1 end time:
+ if( caption.end == 0 || caption.end == -1)
+ continue;
+
+ if( time >= caption.start &&
+ time <= caption.end ) {
+ // set the earliest valid time to the current start index:
+ if( !firstCapIndex ){
+ firstCapIndex = caption.start;
+ }
+
+ //mw.log("Start cap time: " + caption.start + ' End time: ' + caption.end );
+ captionSet[i] = caption ;
+ }
+ // captions are stored in start order stop search if we get larger than time
+ if( caption.start > time ){
+ break;
+ }
+ }
+ // Update the prevIndex:
+ this.prevIndex = firstCapIndex;
+ //Return the set of captions in range:
+ return captionSet;
+ },
+
+ /**
+ * Check if the caption is an overlay format ( and must be ontop of the player )
+ */
+ isOverlay: function(){
+ return this.mimeType == 'text/xml';
+ },
+
+ getCaptions: function( data ){
+ // Detect caption data type:
+ switch( this.mimeType ){
+ case 'text/mw-srt':
+ return this.getCaptiosnFromMediaWikiSrt( data );
+ break;
+ case 'text/x-srt':
+ return this.getCaptionsFromSrt( data);
+ break;
+ case 'text/xml':
+ return this.getCaptionsFromTMML( data );
+ break;
+ }
+ // caption mime not found return empty set:
+ return [];
+ },
+
+ getStyleCssById: function( styleId ){
+ if( this.styleCss[ styleId ] ){
+ return this.styleCss[ styleId ];
+ }
+ return {};
+ },
+ /**
+ * Grab timed text from TMML format
+ *
+ * @param data
+ * @return
+ */
+ getCaptionsFromTMML: function( data ){
+ var _this = this;
+ mw.log("TextSource::getCaptionsFromTMML", data);
+ // set up display information:
+ var captions = [];
+ var xml = ( $( data ).find("tt").length ) ? data : $.parseXML( data );
+
+ // Check for parse error:
+ try {
+ if( !xml || $( xml ).find('parsererror').length ){
+ mw.log("Error: close caption parse error: " + $( xml ).find('parsererror').text() );
+ return captions;
+ }
+ } catch ( e ) {
+ mw.log( "Error: close caption parse error: " + e.toString() );
+ return captions;
+ }
+
+ // Set the body Style
+ var bodyStyleId = $( xml ).find('body').attr('style');
+
+ // Set style translate ttml to css
+ $( xml ).find( 'style').each( function( inx, style){
+ var cssObject = {};
+ // Map CamelCase css properties:
+ $( style.attributes ).each(function(inx, attr){
+ var attrName = attr.name;
+ if( attrName.substr(0, 4) !== 'tts:' ){
+ // skip
+ return true;
+ }
+ var cssName = '';
+ for( var c = 4; c < attrName.length; c++){
+ if( attrName[c].toLowerCase() != attrName[c] ){
+ cssName += '-' + attrName[c].toLowerCase();
+ } else {
+ cssName+= attrName[c]
+ }
+ }
+ cssObject[ cssName ] = attr.nodeValue;
+ });
+ // for(var i =0; i< style.length )
+ _this.styleCss[ $( style).attr('id') ] = cssObject;
+ });
+
+ $( xml ).find( 'p' ).each( function( inx, p ){
+ // Get text content by converting ttml node to html
+ var content = '';
+ $.each( p.childNodes, function(inx, node){
+ content+= _this.convertTTML2HTML( node );
+ });
+ // Get the end time:
+ var end = null;
+ if( $( p ).attr( 'end' ) ){
+ end = mw.npt2seconds( $( p ).attr( 'end' ) );
+ }
+ // Look for dur
+ if( !end && $( p ).attr( 'dur' )){
+ end = mw.npt2seconds( $( p ).attr( 'begin' ) ) +
+ mw.npt2seconds( $( p ).attr( 'dur' ) );
+ }
+
+ // Create the caption object :
+ var captionObj ={
+ 'start': mw.npt2seconds( $( p ).attr( 'begin' ) ),
+ 'end': end,
+ 'content': content
+ };
+
+ // See if we have custom metadata for position of this caption object
+ // there are 35 columns across and 15 rows high
+ var $meta = $(p).find( 'metadata' );
+ if( $meta.length ){
+ captionObj['css'] = {
+ 'position': 'absolute'
+ };
+ if( $meta.attr('cccol') ){
+ captionObj['css']['left'] = ( $meta.attr('cccol') / 35 ) * 100 +'%';
+ // also means the width has to be reduced:
+ //captionObj['css']['width'] = 100 - parseInt( captionObj['css']['left'] ) + '%';
+ }
+ if( $meta.attr('ccrow') ){
+ captionObj['css']['top'] = ( $meta.attr('ccrow') / 15 ) * 100 +'%';
+ }
+ }
+ if( $(p).attr('tts:textAlign') ){
+ if( !captionObj['css'] ){
+ captionObj['css'] = {};
+ }
+ captionObj['css']['text-align'] = $(p).attr('tts:textAlign');
+
+ // Remove text align is "right" flip the css left:
+ if( captionObj['css']['text-align'] == 'right' && captionObj['css']['left'] ){
+ //captionObj['css']['width'] = captionObj['css']['left'];
+ captionObj['css']['left'] = null;
+ }
+ }
+
+ // check if this p has any style else use the body parent
+ if( $(p).attr('style') ){
+ captionObj['styleId'] = $(p).attr('style') ;
+ } else {
+ captionObj['styleId'] = bodyStyleId;
+ }
+ captions.push( captionObj);
+ });
+ return captions;
+ },
+ convertTTML2HTML: function( node ){
+ var _this = this;
+
+ // look for text node:
+ if( node.nodeType == 3 ){
+ return node.textContent;
+ }
+ // skip metadata nodes:
+ if( node.nodeName == 'metadata' ){
+ return '';
+ }
+ // if a br just append
+ if( node.nodeName == 'br' ){
+ return '<br />';
+ }
+ // Setup tts mappings TODO should be static property of a ttmlSource object.
+ var ttsStyleMap = {
+ 'tts:color' : 'color',
+ 'tts:fontWeight' : 'font-weight',
+ 'tts:fontStyle' : 'font-style'
+ };
+ if( node.childNodes.length ){
+ var nodeString = '';
+ var styleVal = '';
+ for( var attr in ttsStyleMap ){
+ if( node.getAttribute( attr ) ){
+ styleVal+= ttsStyleMap[ attr ] + ':' + node.getAttribute( attr ) + ';';
+ }
+ }
+ nodeString += '<' + node.nodeName + ' style="' + styleVal + '" >';
+ $.each( node.childNodes, function( inx, childNode ){
+ nodeString += _this.convertTTML2HTML( childNode );
+ });
+ nodeString += '</' + node.nodeName + '>';
+ return nodeString;
+ }
+ },
+ /**
+ * srt timed text parse handle:
+ * @param {String} data Srt string to be parsed
+ */
+ getCaptionsFromSrt: function ( data ){
+ mw.log("TextSource::getCaptionsFromSrt");
+ var _this = this;
+ // Check if the "srt" parses as an XML
+ try{
+ var xml = $.parseXML( data );
+ if( xml && $( xml ).find('parsererror').length == 0 ){
+ return this.getCaptionsFromTMML( data );
+ }
+ } catch ( e ){
+ // srt should not be xml
+ }
+ // Remove dos newlines
+ var srt = data.replace(/\r+/g, '');
+
+ // Trim white space start and end
+ srt = srt.replace(/^\s+|\s+$/g, '');
+
+ // Remove all html tags for security reasons
+ srt = srt.replace(/<[a-zA-Z\/][^>]*>/g, '');
+
+ // Get captions
+ var captions = [];
+ var caplist = srt.split('\n\n');
+ for (var i = 0; i < caplist.length; i++) {
+ var captionText = "";
+ var caption = false;
+ captionText = caplist[i];
+ var s = captionText.split(/\n/);
+ if (s.length < 2) {
+ // file format error or comment lines
+ continue;
+ }
+ if (s[0].match(/^\d+$/) && s[1].match(/\d+:\d+:\d+/)) {
+ // ignore caption number in s[0]
+ // parse time string
+ var m = s[1].match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/);
+ if (m) {
+ caption = _this.match2caption( m );
+ } else {
+ // Unrecognized timestring
+ continue;
+ }
+ if( caption ){
+ // concatenate text lines to html text
+ caption['content'] = s.slice(2).join("<br>");
+ }
+ } else {
+ // file format error or comment lines
+ continue;
+ }
+ // Add the current caption to the captions set:
+ captions.push( caption );
+ }
+
+ return captions;
+ },
+
+ /**
+ * Get srts from a mediawiki html / srt string
+ *
+ * Right now wiki -> html is not always friendly to our srt parsing.
+ * The long term plan is to move the srt parsing to server side and have the api
+ * server up the srt's times in JSON form
+ *
+ * Also see https://bugzilla.wikimedia.org/show_bug.cgi?id=29126
+ *
+ * TODO move to mediaWiki specific module.
+ */
+ getCaptiosnFromMediaWikiSrt: function( data ){
+ mw.log("TimedText::getCaptiosnFromMediaWikiSrt:");
+ var _this = this;
+ var captions = [ ];
+ var curentCap = {
+ 'content': ''
+ };
+ var parseNextAsTime = false;
+ // Note this string concatenation and html error wrapping sometimes causes
+ // parse issues where the wikitext includes many native <p /> tags without child
+ // subtitles. In prating this is not a deal breakers because the wikitext for
+ // TimedText namespace and associated srts already has a specific format.
+ // Long term we will move to server side parsing.
+ $( '<div>' + data + '</div>' ).find('p').each( function() {
+ var currentPtext = $(this).html();
+ //mw.log( 'pText: ' + currentPtext );
+
+ // We translate raw wikitext gennerated html into a matched srt time sample.
+ // The raw html looks like:
+ // #
+ // hh:mm:ss,ms --&gt hh:mm:ss,ms
+ // text
+ //
+ // You can read more about the srt format here:
+ // http://en.wikipedia.org/wiki/SubRip
+ //
+ // We attempt to be fairly robust in our regular expression to catch a few
+ // srt variations such as omition of commas and empty text lines.
+ var m = currentPtext
+ .replace('--&gt;', '-->') // restore --&gt with --> for easier srt parsing:
+ .match(/\d+\s([\d\-]+):([\d\-]+):([\d\-]+)(?:,([\d\-]+))?\s*--?>\s*([\d\-]+):([\d\-]+):([\d\-]+)(?:,([\d\-]+))?\n?(.*)/);
+
+ if (m) {
+ captions.push(
+ _this.match2caption( m )
+ );
+ return true;
+ }
+
+ /***
+ * Handle multi line sytle output
+ *
+ * Handles cases parse cases where an entire line can't be parsed in the single
+ * regular expression above, Since the diffrent captions pars are outputed in
+ * diffrent <p /> tags by the wikitext parser output.
+ */
+
+ // Check if we have reached the end of a multi line match
+ if( parseInt( currentPtext ) == currentPtext ) {
+ if( curentCap.content != '' ) {
+ captions.push( curentCap );
+ }
+ // Clear out the current caption content
+ curentCap = {
+ 'content': ''
+ };
+ return true;
+ }
+ // Check only for time match:
+ var m = currentPtext
+ .replace('--&gt;', '-->')
+ .match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/);
+ if (m) {
+ // Update the currentCap:
+ curentCap = _this.match2caption( m );
+ return true;
+ }
+ // Else append contnet for the curentCap
+ if( currentPtext != '<br>' ) {
+ curentCap['content'] += currentPtext;
+ }
+ });
+ //Push last subtitle:
+ if( curentCap.length != 0) {
+ captions.push( curentCap );
+ }
+ mw.log( "TimedText::getCaptiosnFromMediaWikiSrt found " + captions.length + ' captions');
+ return captions;
+ },
+ /**
+ * Takes a regular expresion match and converts it to a caption object
+ */
+ match2caption: function( m ){
+ var caption = {};
+ // Look for ms:
+ var startMs = (m[4]) ? parseInt(m[4], 10) : 0;
+ var endMs = (m[8]) ? parseInt(m[8], 10) : 0;
+ caption['start'] = this.timeParts2seconds( m[1], m[2], m[3], startMs );
+ caption['end'] = this.timeParts2seconds( m[5], m[6], m[7], endMs );
+ if( m[9] ){
+ caption['content'] = $.trim( m[9] );
+ }
+ return caption;
+ },
+ /**
+ * Takes time parts in hours, min, seconds and milliseconds and coverts to float seconds.
+ */
+ timeParts2seconds: function( hours, min, sec, ms ){
+ return mw.measurements2seconds({
+ 'hours': hours,
+ 'minutes': min,
+ 'seconds' : sec,
+ 'milliseconds': ms
+ });
+ }
+ };
+
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js
new file mode 100644
index 00000000..2a69343e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js
@@ -0,0 +1,1313 @@
+/**
+ * The Core timed Text interface object
+ *
+ * handles class mappings for:
+ * menu display ( jquery.ui themeable )
+ * timed text loading request
+ * timed text edit requests
+ * timed text search & seek interface ( version 2 )
+ *
+ * @author: Michael Dale
+ *
+ */
+
+( function( mw, $ ) {"use strict";
+
+ // Merge in timed text related attributes:
+ mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [
+ 'srclang',
+ 'kind',
+ 'label'
+ ]);
+
+ /**
+ * Timed Text Object
+ * @param embedPlayer Host player for timedText interfaces
+ */
+ mw.TimedText = function( embedPlayer ) {
+ return this.init( embedPlayer );
+ };
+
+ mw.TimedText.prototype = {
+
+ /**
+ * Preferences config order is presently:
+ * 1) user cookie
+ * 2) defaults provided in this config var:
+ */
+ config: {
+ // Layout for basic "timedText" type can be 'ontop', 'off', 'below'
+ 'layout' : 'ontop',
+
+ //Set the default local ( should be grabbed from the browser )
+ 'userLanguage' : mw.config.get( 'wgUserLanguage' ) || 'en',
+
+ //Set the default kind of timedText to display ( un-categorized timed-text is by default "subtitles" )
+ 'userKind' : 'subtitles'
+ },
+
+ // The default display mode is 'ontop'
+ defaultDisplayMode : 'ontop',
+
+ // Save last layout mode
+ lastLayout : 'ontop',
+
+ // The bind prefix:
+ bindPostFix: '.timedText',
+
+ // Default options are empty
+ options: {},
+
+ /**
+ * The list of enabled sources
+ */
+ enabledSources: [],
+
+ // First loading flag - To set the layout at first load
+ firstLoad: true,
+
+ /**
+ * The current language key
+ */
+ currentLangKey : null,
+
+ /**
+ * The direction of the current language
+ */
+ currentLangDir : null,
+
+ /**
+ * Stores the last text string per kind to avoid dom checks for updated text
+ */
+ prevText: [],
+
+ /**
+ * Text sources ( a set of textSource objects )
+ */
+ textSources: [],
+
+ /**
+ * Valid "Track" categories
+ */
+ validCategoriesKeys: [
+ "CC",
+ "SUB",
+ "TAD",
+ "KTV",
+ "TIK",
+ "AR",
+ "NB",
+ "META",
+ "TRX",
+ "LRC",
+ "LIN",
+ "CUE"
+ ],
+
+ /**
+ * @constructor
+ * @param {Object} embedPlayer Host player for timedText interfaces
+ */
+ init: function( embedPlayer ) {
+ var _this = this;
+ mw.log("TimedText: init() ");
+ this.embedPlayer = embedPlayer;
+ // don't display captions on native player:
+ if( embedPlayer.useNativePlayerControls() ){
+ return this;
+ }
+
+ // Load user preferences config:
+ var preferenceConfig = $.cookie( 'TimedText.Preferences' );
+ if( preferenceConfig !== "false" && preferenceConfig != null ) {
+ this.config = JSON.parse( preferenceConfig );
+ }
+ // remove any old bindings on change media:
+ $( this.embedPlayer ).bind( 'onChangeMedia' + this.bindPostFix , function(){
+ _this.destroy();
+ });
+
+ // Remove any old bindings before we add the current bindings:
+ _this.destroy();
+
+ // Add player bindings
+ _this.addPlayerBindings();
+ return this;
+ },
+ destroy: function(){
+ // remove any old player bindings;
+ $( this.embedPlayer ).unbind( this.bindPostFix );
+ // Clear out enabled sources:
+ this.enabledSources = [];
+ // Clear out text sources:
+ this.textSources = [];
+ },
+ /**
+ * Add timed text related player bindings
+ * @return
+ */
+ addPlayerBindings: function(){
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+
+ // Check for timed text support:
+ _this.addInterface();
+
+ $( embedPlayer ).bind( 'timeupdate' + this.bindPostFix, function( event, jEvent, id ) {
+ // regain scope
+ _this = $('#' + id)[0].timedText;
+ // monitor text updates
+ _this.monitor();
+ } );
+
+ $( embedPlayer ).bind( 'firstPlay' + this.bindPostFix, function(event, id ) {
+ // regain scope
+ _this = $('#' + id)[0].timedText;
+ // Will load and setup timedText sources (if not loaded already loaded )
+ _this.setupTextSources();
+ // Hide the caption menu if presently displayed
+ $( '#textMenuContainer_' + _this.embedPlayer.id ).hide();
+ } );
+
+ // Re-Initialize when changing media
+ $( embedPlayer ).bind( 'onChangeMedia' + this.bindPostFix, function() {
+ _this.destroy();
+ _this.updateLayout();
+ _this.setupTextSources();
+ $( '#textMenuContainer_' + embedPlayer.id ).hide();
+ } );
+
+ // Resize the timed text font size per window width
+ $( embedPlayer ).bind( 'onCloseFullScreen' + this.bindPostFix + ' onOpenFullScreen' + this.bindPostFix, function() {
+ // Check if we are in fullscreen or not, if so add an additional bottom offset of
+ // double the default bottom padding.
+ var textOffset = _this.embedPlayer.controlBuilder.inFullScreen ?
+ mw.config.get("TimedText.BottomPadding") * 2 :
+ mw.config.get("TimedText.BottomPadding");
+
+ var textCss = _this.getInterfaceSizeTextCss({
+ 'width' : embedPlayer.getInterface().width(),
+ 'height' : embedPlayer.getInterface().height()
+ });
+
+ mw.log( 'TimedText::set text size for: : ' + embedPlayer.getInterface().width() + ' = ' + textCss['font-size'] );
+ if ( embedPlayer.controlBuilder.isOverlayControls() && !embedPlayer.getInterface().find( '.control-bar' ).is( ':hidden' ) ) {
+ textOffset += _this.embedPlayer.controlBuilder.getHeight();
+ }
+ embedPlayer.getInterface().find( '.track' )
+ .css( textCss )
+ .css({
+ // Get the text size scale then set it to control bar height + TimedText.BottomPadding;
+ 'bottom': textOffset + 'px'
+ });
+ });
+
+ // Update the timed text size
+ $( embedPlayer ).bind( 'updateLayout'+ this.bindPostFix, function() {
+ // If the the player resize action is an animation, animate text resize,
+ // else instantly adjust the css.
+ var textCss = _this.getInterfaceSizeTextCss( {
+ 'width': embedPlayer.getPlayerWidth(),
+ 'height': embedPlayer.getPlayerHeight()
+ });
+ mw.log( 'TimedText::updateLayout: ' + textCss['font-size']);
+ embedPlayer.getInterface().find( '.track' ).css( textCss );
+ });
+
+ // Setup display binding
+ $( embedPlayer ).bind( 'onShowControlBar'+ this.bindPostFix, function(event, layout, id ){
+ // update embedPlayer ref:
+ var embedPlayer = $('#' + id )[0];
+ if ( embedPlayer.controlBuilder.isOverlayControls() ) {
+ // Move the text track if present
+ embedPlayer.getInterface().find( '.track' )
+ .stop()
+ .animate( layout, 'fast' );
+ }
+ });
+
+ $( embedPlayer ).bind( 'onHideControlBar' + this.bindPostFix, function(event, layout, id ){
+ var embedPlayer = $('#' + id )[0];
+ if ( embedPlayer.controlBuilder.isOverlayControls() ) {
+ // Move the text track down if present
+ embedPlayer.getInterface().find( '.track' )
+ .stop()
+ .animate( layout, 'fast' );
+ }
+ });
+
+ $( embedPlayer ).bind( 'AdSupport_StartAdPlayback' + this.bindPostFix, function() {
+ if ( $( '#textMenuContainer_' + embedPlayer.id ).length ) {
+ $( '#textMenuContainer_' + embedPlayer.id ).hide();
+ }
+ var $textButton = embedPlayer.getInterface().find( '.timed-text' );
+ if ( $textButton.length ) {
+ $textButton.unbind( 'click' );
+ }
+ _this.lastLayout = _this.getLayoutMode();
+ _this.setLayoutMode( 'off' );
+ } );
+
+ $( embedPlayer ).bind( 'AdSupport_EndAdPlayback' + this.bindPostFix, function() {
+ var $textButton = embedPlayer.getInterface().find( '.timed-text' );
+ if ( $textButton.length ) {
+ _this.bindTextButton( $textButton );
+ }
+ _this.setLayoutMode( _this.lastLayout );
+ } );
+
+ },
+ addInterface: function(){
+ var _this = this;
+ // By default we include a button in the control bar.
+ $( _this.embedPlayer ).bind( 'addControlBarComponent' + this.bindPostFix, function(event, controlBar ){
+ if( controlBar.supportedComponents['timedText'] !== false &&
+ _this.includeCaptionButton() ) {
+ controlBar.supportedComponents['timedText'] = true;
+ controlBar.components['timedText'] = _this.getTimedTextButton();
+ }
+ });
+ },
+ includeCaptionButton:function(){
+ return mw.config.get( 'TimedText.ShowInterface' ) == 'always' ||
+ this.embedPlayer.getTextTracks().length;
+ },
+ /**
+ * Get the current language key
+ * @return
+ * @type {string}
+ */
+ getCurrentLangKey: function(){
+ return this.currentLangKey;
+ },
+ /**
+ * Get the current language direction
+ * @return
+ * @type {string}
+ */
+ getCurrentLangDir: function(){
+ if ( !this.currentLangDir ) {
+ var source = this.getSourceByLanguage( this.getCurrentLangKey() );
+ this.currentLangDir = source.dir;
+ }
+ return this.currentLangDir;
+ },
+
+ /**
+ * The timed text button to be added to the interface
+ */
+ getTimedTextButton: function(){
+ var _this = this;
+ /**
+ * The closed captions button
+ */
+ return {
+ 'w': 30,
+ 'position': 6.9,
+ 'o': function( ctrlObj ) {
+ var $textButton = $( '<div />' )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-timed_text' ) )
+ .addClass( "ui-state-default ui-corner-all ui-icon_link rButton timed-text" )
+ .append(
+ $( '<span />' )
+ .addClass( "ui-icon ui-icon-comment" )
+ )
+ // Captions binding:
+ .buttonHover();
+ _this.bindTextButton( $textButton );
+ return $textButton;
+
+ }
+ };
+ },
+ bindTextButton: function( $textButton ){
+ var _this = this;
+ $textButton.unbind('click.textMenu').bind('click.textMenu', function() {
+ _this.showTextMenu();
+ return true;
+ } );
+ },
+
+ /**
+ * Get the fullscreen text css
+ */
+ getInterfaceSizeTextCss: function( size ) {
+ //mw.log(' win size is: ' + $( window ).width() + ' ts: ' + textSize );
+ return {
+ 'font-size' : this.getInterfaceSizePercent( size ) + '%'
+ };
+ },
+
+ /**
+ * Show the text interface library and show the text interface near the player.
+ */
+ showTextMenu: function() {
+ var embedPlayer = this.embedPlayer;
+ var loc = embedPlayer.getInterface().find( '.rButton.timed-text' ).offset();
+ mw.log('TimedText::showTextMenu:: ' + embedPlayer.id + ' location: ', loc);
+ // TODO: Fix menu animation
+ var $menuButton = this.embedPlayer.getInterface().find( '.timed-text' );
+ // Check if a menu has already been built out for the menu button:
+ if ( $menuButton[0].m ) {
+ $menuButton.embedMenu( 'show' );
+ } else {
+ // Bind the text menu:
+ this.buildMenu( true );
+ }
+ },
+ getTextMenuContainer: function(){
+ var textMenuId = 'textMenuContainer_' + this.embedPlayer.id;
+ if( !$( '#' + textMenuId ).length ){
+ //Setup the menu:
+ this.embedPlayer.getInterface().append(
+ $('<div>')
+ .addClass('ui-widget ui-widget-content ui-corner-all')
+ .attr( 'id', textMenuId )
+ .css( {
+ 'position' : 'absolute',
+ 'height' : '180px',
+ 'width' : '180px',
+ 'font-size' : '12px',
+ 'display' : 'none',
+ 'overflow' : 'auto'
+ } )
+
+ );
+ }
+ return $( '#' + textMenuId );
+ },
+ /**
+ * Gets a text size percent relative to about 30 columns of text for 400
+ * pixel wide player, at 100% text size.
+ *
+ * @param size {object} The size of the target player area width and height
+ */
+ getInterfaceSizePercent: function( size ) {
+ // This is a ugly hack we should read "original player size" and set based
+ // on some standard ish normal 31 columns 15 rows
+ var sizeFactor = 4;
+ if( size.height / size.width < .7 ){
+ sizeFactor = 6;
+ }
+ var textSize = size.width / sizeFactor;
+ if( textSize < 95 ){
+ textSize = 95;
+ }
+ if( textSize > 150 ){
+ textSize = 150;
+ }
+ return textSize;
+ },
+
+ /**
+ * Setups available text sources
+ * loads text sources
+ * auto-selects a source based on the user language
+ * @param {Function} callback Function to be called once text sources are setup.
+ */
+ setupTextSources: function( callback ) {
+ mw.log( 'TimedText::setupTextSources');
+ var _this = this;
+ // Load textSources
+ _this.loadTextSources( function() {
+ // Enable a default source and issue a request to "load it"
+ _this.autoSelectSource();
+
+ // Load and parse the text value of enabled text sources:
+ _this.loadEnabledSources();
+
+ if( callback ) {
+ callback();
+ }
+ } );
+ },
+
+ /**
+ * Binds the timed text menu
+ * and updates its content from "getMainMenu"
+ *
+ * @param {Object} target to display the menu
+ * @param {Boolean} autoShow If the menu should be displayed
+ */
+ buildMenu: function( autoShow ) {
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ // Setup text sources ( will callback inline if already loaded )
+ _this.setupTextSources( function() {
+ var $menuButton = _this.embedPlayer.getInterface().find( '.timed-text' );
+
+ var positionOpts = { };
+ if( _this.embedPlayer.supports[ 'overlays' ] ){
+ var positionOpts = {
+ 'directionV' : 'up',
+ 'offsetY' : _this.embedPlayer.controlBuilder.getHeight(),
+ 'directionH' : 'left',
+ 'offsetX' : -28
+ };
+ }
+
+ if( !_this.embedPlayer.getInterface() ){
+ mw.log("TimedText:: interface called before interface ready, just wait for interface");
+ return ;
+ }
+ var $menuButton = _this.embedPlayer.getInterface().find( '.timed-text' );
+ var ctrlObj = _this.embedPlayer.controlBuilder;
+ // NOTE: Button target should be an option or config
+ $menuButton.embedMenu( {
+ 'content' : _this.getMainMenu(),
+ 'zindex' : mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 2,
+ 'crumbDefaultText' : ' ',
+ 'autoShow': autoShow,
+ 'keepPosition' : true,
+ 'showSpeed': 0,
+ 'height' : 100,
+ 'width' : 300,
+ 'targetMenuContainer' : _this.getTextMenuContainer(),
+ 'positionOpts' : positionOpts,
+ 'backLinkText' : mw.msg( 'mwe-timedtext-back-btn' ),
+ 'createMenuCallback' : function(){
+ var $interface = _this.embedPlayer.getInterface();
+ var $textContainer = _this.getTextMenuContainer();
+ var textHeight = 130;
+ var top = $interface.height() - textHeight - ctrlObj.getHeight() - 6;
+ if( top < 0 ){
+ top = 0;
+ }
+ // check for audio
+ if( _this.embedPlayer.isAudio() ){
+ top = _this.embedPlayer.controlBuilder.getHeight() + 4;
+ }
+ $textContainer.css({
+ 'top' : top,
+ 'height': textHeight,
+ 'position' : 'absolute',
+ 'left': $menuButton[0].offsetLeft - 165,
+ 'bottom': ctrlObj.getHeight()
+ })
+ ctrlObj.showControlBar( true );
+ },
+ 'closeMenuCallback' : function(){
+ ctrlObj.restoreControlsHover();
+ }
+ });
+ });
+ },
+
+ /**
+ * Monitor video time and update timed text filed[s]
+ */
+ monitor: function() {
+ //mw.log(" timed Text monitor: " + this.enabledSources.length );
+ var embedPlayer = this.embedPlayer;
+ // Setup local reference to currentTime:
+ var currentTime = embedPlayer.currentTime;
+
+ // Get the text per kind
+ var textCategories = [ ];
+
+ var source = this.enabledSources[ 0 ];
+ if( source ) {
+ this.updateSourceDisplay( source, currentTime );
+ }
+ },
+
+ /**
+ * Load all the available text sources from the inline embed
+ * @param {Function} callback Function to call once text sources are loaded
+ */
+ loadTextSources: function( callback ) {
+ var _this = this;
+ // check if text sources are already loaded ( not em )
+ if( this.textSources.length ){
+ callback( this.textSources );
+ return ;
+ }
+ this.textSources = [];
+ // load inline text sources:
+ $.each( this.embedPlayer.getTextTracks(), function( inx, textSource ){
+ _this.textSources.push( new mw.TextSource( textSource ) );
+ });
+ // return the callback with sources
+ callback( _this.textSources );
+ },
+
+ /**
+ * Get the layout mode
+ *
+ * Takes into consideration:
+ * Playback method overlays support ( have to put subtitles below video )
+ *
+ */
+ getLayoutMode: function() {
+ // Re-map "ontop" to "below" if player does not support
+ if( this.config.layout == 'ontop' && !this.embedPlayer.supports['overlays'] ) {
+ this.config.layout = 'below';
+ }
+ return this.config.layout;
+ },
+
+ /**
+ * Auto selects a source given the local configuration
+ *
+ * NOTE: presently this selects a "single" source.
+ * In the future we could support multiple "enabled sources"
+ */
+ autoSelectSource: function() {
+ var _this = this;
+ // If a source is enabled then don't auto select
+ if ( this.enabledSources.length ) {
+ return false;
+ }
+ this.enabledSources = [];
+
+ var setDefault = false;
+ // Check if any source is marked default:
+ $.each( this.textSources, function(inx, source){
+ if( source['default'] ){
+ _this.enableSource( source );
+ setDefault = true;
+ return false;
+ }
+ });
+ if ( setDefault ) {
+ return true;
+ }
+
+ var setLocalPref = false;
+ // Check if any source matches our "local" pref
+ $.each( this.textSources, function(inx, source){
+ if( _this.config.userLanguage == source.srclang.toLowerCase()
+ &&
+ _this.config.userKind == source.kind
+ ) {
+ _this.enableSource( source );
+ setLocalPref = true;
+ return false;
+ }
+ });
+ if ( setLocalPref ) {
+ return true;
+ }
+
+ var setEnglish = false;
+ // If no userLang, source try enabling English:
+ if( this.enabledSources.length == 0 ) {
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ if( source.srclang.toLowerCase() == 'en' ) {
+ _this.enableSource( source );
+ setEnglish = true;
+ return false;
+ }
+ }
+ }
+ if ( setEnglish ) {
+ return true;
+ }
+
+ var setFirst = false;
+ // If still no source try the first source we get;
+ if( this.enabledSources.length == 0 ) {
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ _this.enableSource( source );
+ setFirst = true;
+ return false;
+ }
+ }
+ if ( setFirst ) {
+ return true;
+ }
+
+ return false;
+ },
+ /**
+ * Enable a source and update the currentLangKey
+ * @param {object} source
+ * @return
+ */
+ enableSource: function( source ){
+ var _this = this;
+ // check if we have any source set yet:
+ if( !_this.enabledSources.length ){
+ _this.enabledSources.push( source );
+ _this.currentLangKey = source.srclang;
+ _this.currentLangDir = null;
+ return ;
+ }
+ var sourceEnabled = false;
+ // Make sure the source is not already enabled
+ $.each( this.enabledSources, function( inx, enabledSource ){
+ if( source.id == enabledSource.id ){
+ sourceEnabled = true;
+ }
+ });
+ if ( !sourceEnabled ) {
+ _this.enabledSources.push( source );
+ _this.currentLangKey = source.srclang;
+ _this.currentLangDir = null;
+ }
+ },
+
+ /**
+ * Get the current source sub captions
+ * @param {function} callback function called once source is loaded
+ */
+ loadCurrentSubSource: function( callback ){
+ mw.log("loadCurrentSubSource:: enabled source:" + this.enabledSources.length);
+ for( var i =0; i < this.enabledSources.length; i++ ){
+ var source = this.enabledSources[i];
+ if( source.kind == 'SUB' ){
+ source.load( function(){
+ callback( source);
+ return ;
+ });
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Get sub captions by language key:
+ *
+ * @param {string} langKey Key of captions to load
+ * @pram {function} callback function called once language key is loaded
+ */
+ getSubCaptions: function( langKey, callback ){
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ if( source.srclang.toLowerCase() === langKey ) {
+ var source = this.textSources[ i ];
+ source.load( function(){
+ callback( source.captions );
+ });
+ }
+ }
+ },
+
+ /**
+ * Issue a request to load all enabled Sources
+ * Should be called anytime enabled Source list is updated
+ */
+ loadEnabledSources: function() {
+ var _this = this;
+ mw.log( "TimedText:: loadEnabledSources " + this.enabledSources.length );
+ $.each( this.enabledSources, function( inx, enabledSource ) {
+ // check if the source requires ovelray ( ontop ) layout mode:
+ if( enabledSource.isOverlay() && _this.config.layout== 'ontop' ){
+ _this.setLayoutMode( 'ontop' );
+ }
+ enabledSource.load(function(){
+ // Trigger the text loading event:
+ $( _this.embedPlayer ).trigger('loadedTextSource', enabledSource);
+ });
+ });
+ },
+ /**
+ * Checks if a source is "on"
+ * @return {Boolean}
+ * true if source is on
+ * false if source is off
+ */
+ isSourceEnabled: function( source ) {
+ // no source is "enabled" if subtitles are "off"
+ if( this.getLayoutMode() == 'off' ){
+ return false;
+ }
+ var isEnabled = false;
+ $.each( this.enabledSources, function( inx, enabledSource ) {
+ if( source.id ) {
+ if( source.id === enabledSource.id ){
+ isEnabled = true;
+ }
+ }
+ if( source.src ){
+ if( source.src == enabledSource.src ){
+ isEnabled = true;
+ }
+ }
+ });
+ return isEnabled;
+ },
+
+ /**
+ * Marks the active captions in the menu
+ */
+ markActive: function( source ) {
+ var $menu = $( '#textMenuContainer_' + this.embedPlayer.id );
+ if ( $menu.length ) {
+ var $captionRows = $menu.find( '.captionRow' );
+ if ( $captionRows.length ) {
+ $captionRows.each( function() {
+ $( this ).removeClass( 'ui-icon-bullet ui-icon-radio-on' );
+ var iconClass = ( $( this ).data( 'caption-id' ) === source.id ) ? 'ui-icon-bullet' : 'ui-icon-radio-on';
+ $( this ).addClass( iconClass );
+ } );
+ }
+ }
+ },
+
+ /**
+ * Marks the active layout mode in the menu
+ */
+ markLayoutActive: function ( layoutMode ) {
+ var $menu = $( '#textMenuContainer_' + this.embedPlayer.id );
+ if ( $menu.length ) {
+ var $layoutRows = $menu.find( '.layoutRow' );
+ if ( $layoutRows.length ) {
+ $layoutRows.each( function() {
+ $( this ).removeClass( 'ui-icon-bullet ui-icon-radio-on' );
+ var iconClass = ( $( this ).data( 'layoutMode' ) === layoutMode ) ? 'ui-icon-bullet' : 'ui-icon-radio-on';
+ $( this ).addClass( iconClass );
+ } );
+ }
+ }
+ },
+
+ /**
+ * Get a source object by language, returns "false" if not found
+ * @param {string} langKey The language key filter for selected source
+ */
+ getSourceByLanguage: function ( langKey ) {
+ for(var i=0; i < this.textSources.length; i++) {
+ var source = this.textSources[ i ];
+ if( source.srclang == langKey ){
+ return source;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Builds the core timed Text menu and
+ * returns the binded jquery object / dom set
+ *
+ * Assumes text sources have been setup: ( _this.setupTextSources() )
+ *
+ * calls a few sub-functions:
+ * Basic menu layout:
+ * Chose Language
+ * All Subtiles here ( if we have categories list them )
+ * Layout
+ * Below video
+ * Ontop video ( only available to supported plugins )
+ * TODO features:
+ * [ Search Text ]
+ * [ This video ]
+ * [ All videos ]
+ * [ Chapters ] seek to chapter
+ */
+ getMainMenu: function() {
+ var _this = this;
+
+ // Set the menut to avaliable languages:
+ var $menu = _this.getLanguageMenu();
+
+ if( _this.textSources.length == 0 ){
+ $menu.append(
+ $.getLineItem( mw.msg( 'mwe-timedtext-no-subs'), 'close' )
+ );
+ } else {
+ // Layout Menu option if not in an iframe and we can expand video size:
+ $menu.append(
+ $.getLineItem(
+ mw.msg( 'mwe-timedtext-layout-off'),
+ ( _this.getLayoutMode() == 'off' ) ? 'bullet' : 'radio-on',
+ function() {
+ _this.setLayoutMode( 'off' );
+ },
+ 'layoutRow',
+ { 'layoutMode' : 'off' }
+ )
+ )
+ }
+ // Allow other modules to add to the timed text menu:
+ $( _this.embedPlayer ).trigger( 'TimedText_BuildCCMenu', [ $menu, _this.embedPlayer.id ] ) ;
+
+ // Test if only one menu item move its children to the top level
+ if( $menu.children('li').length == 1 ){
+ $menu.find('li > ul > li').detach().appendTo( $menu );
+ $menu.find('li').eq(0).remove();
+ }
+
+ return $menu;
+ },
+
+ /**
+ * Utility function to assist in menu build out:
+ * Get menu line item (li) html: <li><a> msgKey </a></li>
+ *
+ * @param {String} msgKey Msg key for menu item
+ */
+
+ /**
+ * Get line item (li) from source object
+ * @param {Object} source Source to get menu line item from
+ */
+ getLiSource: function( source ) {
+ var _this = this;
+ //See if the source is currently "on"
+ var sourceIcon = ( this.isSourceEnabled( source ) )? 'bullet' : 'radio-on';
+ if( source.title ) {
+ return $.getLineItem( source.title, sourceIcon, function() {
+ _this.selectTextSource( source );
+ }, 'captionRow', { 'caption-id' : source.id } );
+ }
+ if( source.srclang ) {
+ var langKey = source.srclang.toLowerCase();
+ return $.getLineItem(
+ mw.msg('mwe-timedtext-key-language', langKey, _this.getLanguageName ( langKey ) ),
+ sourceIcon,
+ function() {
+ // select the current text source:
+ _this.selectTextSource( source );
+ },
+ 'captionRow',
+ { 'caption-id' : source.id }
+ );
+ }
+ },
+
+ /**
+ * Get language name from language key
+ * @param {String} lang_key Language key
+ */
+ getLanguageName: function( lang_key ) {
+ if( mw.Language.names[ lang_key ]) {
+ return mw.Language.names[ lang_key ];
+ }
+ return false;
+ },
+
+
+ /**
+ * set the layout mode
+ * @param {Object} layoutMode The selected layout mode
+ */
+ setLayoutMode: function( layoutMode ) {
+ var _this = this;
+ mw.log("TimedText:: setLayoutMode: " + layoutMode + ' ( old mode: ' + _this.config.layout + ' )' );
+ if( ( layoutMode != _this.config.layout ) || _this.firstLoad ) {
+ // Update the config and redraw layout
+ _this.config.layout = layoutMode;
+ // Update the display:
+ _this.updateLayout();
+ _this.firstLoad = false;
+ }
+ _this.markLayoutActive( layoutMode );
+ },
+
+ toggleCaptions: function(){
+ mw.log( "TimedText:: toggleCaptions was:" + this.config.layout );
+ if( this.config.layout == 'off' ){
+ this.setLayoutMode( this.defaultDisplayMode );
+ } else {
+ this.setLayoutMode( 'off' );
+ }
+ },
+ /**
+ * Updates the timed text layout ( should be called when config.layout changes )
+ */
+ updateLayout: function() {
+ mw.log( "TimedText:: updateLayout " );
+ var $playerTarget = this.embedPlayer.getInterface();
+ if( $playerTarget ) {
+ // remove any existing caption containers:
+ $playerTarget.find('.captionContainer,.captionsOverlay').remove();
+ }
+ this.refreshDisplay();
+ },
+
+ /**
+ * Select a new source
+ *
+ * @param {Object} source Source object selected
+ */
+ selectTextSource: function( source ) {
+ var _this = this;
+ mw.log("TimedText:: selectTextSource: select lang: " + source.srclang );
+
+ // enable last non-off layout:
+ _this.setLayoutMode( _this.lastLayout );
+
+ // For some reason we lose binding for the menu ~sometimes~ re-bind
+ this.bindTextButton( this.embedPlayer.getInterface().find('timed-text') );
+
+ this.currentLangKey = source.srclang;
+ this.currentLangDir = null;
+
+ // Update the config language if the source includes language
+ if( source.srclang ){
+ this.config.userLanguage = source.srclang;
+ }
+
+ if( source.kind ){
+ this.config.userKind = source.kind;
+ }
+
+ // (@@todo update kind & setup kind language buckets? )
+
+ // Remove any other sources selected in sources kind
+ this.enabledSources = [];
+
+ this.enabledSources.push( source );
+
+ // Set any existing text target to "loading"
+ if( !source.loaded ) {
+ var $playerTarget = this.embedPlayer.getInterface();
+ $playerTarget.find('.track').text( mw.msg('mwe-timedtext-loading-text') );
+ // Load the text:
+ source.load( function(){
+ // Refresh the interface:
+ _this.refreshDisplay();
+ });
+ } else {
+ _this.refreshDisplay();
+ }
+
+ _this.markActive( source );
+
+ // Trigger the event
+ $( this.embedPlayer ).trigger( 'TimedText_ChangeSource' );
+ },
+
+ /**
+ * Refresh the display, updates the timedText layout, menu, and text display
+ * also updates the cookie preference.
+ *
+ * Called after a user option change
+ */
+ refreshDisplay: function() {
+ // Update the configuration object
+ $.cookie( 'TimedText.Preferences', JSON.stringify( this.config ) );
+
+ // Empty out previous text to force an interface update:
+ this.prevText = [];
+
+ // Refresh the Menu (if it has a target to refresh)
+ mw.log( 'TimedText:: bind menu refresh display' );
+ this.buildMenu();
+ this.resizeInterface();
+
+ // add an empty catption:
+ this.displayTextTarget( $( '<span /> ').text( '') );
+
+ // Issues a "monitor" command to update the timed text for the new layout
+ this.monitor();
+ },
+
+ /**
+ * Builds the language source list menu
+ * Cehck if the "track" tags had the "kind" attribute.
+ *
+ * The kind attribute forms "categories" of text tracks like "subtitles",
+ * "audio description", "chapter names". We check for these categories
+ * when building out the language menu.
+ */
+ getLanguageMenu: function() {
+ var _this = this;
+
+ // See if we have categories to worry about
+ // associative array of SUB etc categories. Each kind contains an array of textSources.
+ var categorySourceList = {};
+ var sourcesWithCategoryCount = 0;
+
+ // ( All sources should have a kind (depreciate )
+ var sourcesWithoutCategory = [ ];
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ if( source.kind ) {
+ var categoryKey = source.kind ;
+ // Init Category menu item if it does not already exist:
+ if( !categorySourceList[ categoryKey ] ) {
+ // Set up catList pointer:
+ categorySourceList[ categoryKey ] = [];
+ sourcesWithCategoryCount++;
+ }
+ // Append to the source kind key menu item:
+ categorySourceList[ categoryKey ].push(
+ _this.getLiSource( source )
+ );
+ }else{
+ sourcesWithoutCategory.push( _this.getLiSource( source ) );
+ }
+ }
+ var $langMenu = $('<ul>');
+ // Check if we have multiple categories ( if not just list them under the parent menu item)
+ if( sourcesWithCategoryCount > 1 ) {
+ for(var categoryKey in categorySourceList) {
+ var $catChildren = $('<ul>');
+ for(var i=0; i < categorySourceList[ categoryKey ].length; i++) {
+ $catChildren.append(
+ categorySourceList[ categoryKey ][i]
+ );
+ }
+ // Append a cat menu item for each kind list
+ // Give grep a chance to find the usages:
+ // mwe-timedtext-textcat-cc, mwe-timedtext-textcat-sub, mwe-timedtext-textcat-tad,
+ // mwe-timedtext-textcat-ktv, mwe-timedtext-textcat-tik, mwe-timedtext-textcat-ar,
+ // mwe-timedtext-textcat-nb, mwe-timedtext-textcat-meta, mwe-timedtext-textcat-trx,
+ // mwe-timedtext-textcat-lrc, mwe-timedtext-textcat-lin, mwe-timedtext-textcat-cue
+ $langMenu.append(
+ $.getLineItem( mw.msg( 'mwe-timedtext-textcat-' + categoryKey.toLowerCase() ) ).append(
+ $catChildren
+ )
+ );
+ }
+ } else {
+ for(var categoryKey in categorySourceList) {
+ for(var i=0; i < categorySourceList[ categoryKey ].length; i++) {
+ $langMenu.append(
+ categorySourceList[ categoryKey ][i]
+ );
+ }
+ }
+ }
+ // Add any remaning sources that did nto have a category
+ for(var i=0; i < sourcesWithoutCategory.length; i++) {
+ $langMenu.append( sourcesWithoutCategory[i] );
+ }
+
+ return $langMenu;
+ },
+
+ /**
+ * Updates a source display in the interface for a given time
+ * @param {object} source Source to update
+ * @param {number} time Caption time used to add and remove active captions.
+ */
+ updateSourceDisplay: function ( source, time ) {
+ var _this = this;
+ if( this.timeOffset ){
+ time = time + parseInt( this.timeOffset );
+ }
+
+ // Get the source text for the requested time:
+ var activeCaptions = source.getCaptionForTime( time );
+ var addedCaption = false;
+ // Show captions that are on:
+ $.each( activeCaptions, function( capId, caption ){
+ var $cap = _this.embedPlayer.getInterface().find( '.track[data-capId="' + capId +'"]');
+ if( caption.content != $cap.html() ){
+ // remove old
+ $cap.remove();
+ // add the updated value:
+ _this.addCaption( source, capId, caption );
+ addedCaption = true;
+ }
+ });
+
+ // hide captions that are off:
+ _this.embedPlayer.getInterface().find( '.track' ).each(function( inx, caption){
+ if( !activeCaptions[ $( caption ).attr('data-capId') ] ){
+ if( addedCaption ){
+ $( caption ).remove();
+ } else {
+ $( caption ).fadeOut( mw.config.get('EmbedPlayer.MonitorRate'), function(){$(this).remove();} );
+ }
+ }
+ });
+ },
+ addCaption: function( source, capId, caption ){
+ if( this.getLayoutMode() == 'off' ){
+ return ;
+ }
+
+ // use capId as a class instead of id for easy selections and no conflicts with
+ // multiple players on page.
+ var $textTarget = $('<div />')
+ .addClass( 'track' )
+ .attr( 'data-capId', capId )
+ .hide();
+
+ // Update text ( use "html" instead of "text" so that subtitle format can
+ // include html formating
+ // TOOD we should scrub this for non-formating html
+ $textTarget.append(
+ $('<span>')
+ .addClass( 'ttmlStyled' )
+ .css( 'pointer-events', 'auto')
+ .css( this.getCaptionCss() )
+ .append(
+ $('<span>')
+ // Prevent background (color) overflowing TimedText
+ // http://stackoverflow.com/questions/9077887/avoid-overlapping-rows-in-inline-element-with-a-background-color-applied
+ .css( 'position', 'relative' )
+ .html( caption.content )
+ )
+ );
+
+
+ // Add/update the lang option
+ $textTarget.attr( 'lang', source.srclang.toLowerCase() );
+
+ // Update any links to point to a new window
+ $textTarget.find( 'a' ).attr( 'target', '_blank' );
+
+ // Add TTML or other complex text styles / layouts if we have ontop captions:
+ if( this.getLayoutMode() == 'ontop' ){
+ if( caption.css ){
+ $textTarget.css( caption.css );
+ } else {
+ $textTarget.css( this.getDefaultStyle() );
+ }
+ }
+ // Apply any custom style ( if we are ontop of the video )
+ this.displayTextTarget( $textTarget );
+
+ // apply any interface size adjustments:
+ $textTarget.css( this.getInterfaceSizeTextCss({
+ 'width' : this.embedPlayer.getInterface().width(),
+ 'height' : this.embedPlayer.getInterface().height()
+ })
+ );
+
+ // Update the style of the text object if set
+ if( caption.styleId ){
+ var capCss = source.getStyleCssById( caption.styleId );
+ $textTarget.find('span.ttmlStyled').css(
+ capCss
+ );
+ }
+ $textTarget.fadeIn('fast');
+ },
+ displayTextTarget: function( $textTarget ){
+ var embedPlayer = this.embedPlayer;
+ var $interface = embedPlayer.getInterface();
+ var controlBarHeight = embedPlayer.controlBuilder.getHeight();
+
+ if( this.getLayoutMode() == 'off' ){
+ // sync player size per audio player:
+ if( embedPlayer.isAudio() ){
+ $interface.find( '.overlay-win' ).css( 'top', controlBarHeight );
+ $interface.css( 'height', controlBarHeight );
+ }
+ return;
+ }
+
+ if( this.getLayoutMode() == 'ontop' ){
+ this.addTextOverlay(
+ $textTarget
+ );
+ } else if( this.getLayoutMode() == 'below' ){
+ this.addTextBelowVideo( $textTarget );
+ } else {
+ mw.log("Possible Error, layout mode not recognized: " + this.getLayoutMode() );
+ }
+
+ // sync player size per audio player:
+ if( embedPlayer.isAudio() && embedPlayer.getInterface().height() < 80 ){
+ $interface.find( '.overlay-win' ).css( 'top', 80);
+ $interface.css( 'height', 80 );
+
+ $interface.find('.captionsOverlay' )
+ .css('bottom', embedPlayer.controlBuilder.getHeight() )
+ }
+
+ },
+ getDefaultStyle: function(){
+ var defaultBottom = 15;
+ if( this.embedPlayer.controlBuilder.isOverlayControls() && !this.embedPlayer.getInterface().find( '.control-bar' ).is( ':hidden' ) ) {
+ defaultBottom += this.embedPlayer.controlBuilder.getHeight();
+ }
+ var baseCss = {
+ 'position':'absolute',
+ 'bottom': defaultBottom,
+ 'width': '100%',
+ 'display': 'block',
+ 'opacity': .8,
+ 'text-align': 'center'
+ };
+ baseCss =$.extend( baseCss, this.getInterfaceSizeTextCss({
+ 'width' : this.embedPlayer.getInterface().width(),
+ 'height' : this.embedPlayer.getInterface().height()
+ }));
+ return baseCss;
+ },
+ addTextOverlay: function( $textTarget ){
+ var _this = this;
+ var $captionsOverlayTarget = this.embedPlayer.getInterface().find('.captionsOverlay');
+ var layoutCss = {
+ 'left': 0,
+ 'top': 0,
+ 'bottom': 0,
+ 'right': 0,
+ 'position': 'absolute',
+ 'direction': this.getCurrentLangDir(),
+ 'z-index': mw.config.get( 'EmbedPlayer.FullScreenZIndex' )
+ };
+
+ if( $captionsOverlayTarget.length == 0 ){
+ // TODO make this look more like addBelowVideoCaptionsTarget
+ $captionsOverlayTarget = $( '<div />' )
+ .addClass( 'captionsOverlay' )
+ .css( layoutCss )
+ .css('pointer-events', 'none');
+ this.embedPlayer.getVideoHolder().append( $captionsOverlayTarget );
+ }
+ // Append the text:
+ $captionsOverlayTarget.append( $textTarget );
+
+ },
+ /**
+ * Applies the default layout for a text target
+ */
+ addTextBelowVideo: function( $textTarget ) {
+ var $playerTarget = this.embedPlayer.getInterface();
+ // Get the relative positioned player class from the controlBuilder:
+ this.embedPlayer.controlBuilder.keepControlBarOnScreen = true;
+ if( !$playerTarget.find('.captionContainer').length || this.embedPlayer.useNativePlayerControls() ) {
+ this.addBelowVideoCaptionContainer();
+ }
+ $playerTarget.find('.captionContainer').html(
+ $textTarget.css( {
+ 'color':'white'
+ } )
+ );
+ },
+ addBelowVideoCaptionContainer: function(){
+ var _this = this;
+ mw.log( "TimedText:: addBelowVideoCaptionContainer" );
+ var $playerTarget = this.embedPlayer.getInterface();
+ if( $playerTarget.find('.captionContainer').length ) {
+ return ;
+ }
+ // Append after video container
+ this.embedPlayer.getVideoHolder().after(
+ $('<div>').addClass( 'captionContainer block' )
+ .css({
+ 'width' : '100%',
+ 'height' : mw.config.get( 'TimedText.BelowVideoBlackBoxHeight' ) + 'px',
+ 'background-color' : '#000',
+ 'text-align' : 'center',
+ 'padding-top' : '5px'
+ } )
+ );
+
+ _this.embedPlayer.triggerHelper('updateLayout');
+ },
+ /**
+ * Resize the interface for layoutMode == 'below' ( if not in full screen)
+ */
+ resizeInterface: function(){
+ var _this = this;
+ if( !_this.embedPlayer.controlBuilder ){
+ // too soon
+ return ;
+ }
+ if( !_this.embedPlayer.controlBuilder.inFullScreen && _this.originalPlayerHeight ){
+ _this.embedPlayer.triggerHelper( 'resizeIframeContainer', [{'height' : _this.originalPlayerHeight}] );
+ } else {
+ // removed resize on container content, since syncPlayerSize calls now handle keeping player aspect.
+ _this.embedPlayer.triggerHelper('updateLayout');
+ }
+ },
+ /**
+ * Build css for caption using this.options
+ */
+ getCaptionCss: function() {
+ return {};
+ }
+ };
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css
new file mode 100644
index 00000000..e924ba34
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css
@@ -0,0 +1,18 @@
+.ttmlStyled {
+ color: white;
+ letter-spacing: 0.04em;
+ text-align: center;
+ padding: 0.2em;
+ /*
+ // Text shadow is too slow with current browsers use background-color
+ text-shadow:0 2px 1px #000000, -1px 3px 1px #000000, -2px 2px 1px #000000, -2px 1px 1px #000000, -2px 0 1px #000000, 2px 2px 1px #000000, 1px 2px 1px #000000, 0 -2px 1px #000000, 2px -2px 1px #000000, -2px -1px 1px #000000, -1px -3px 1px #000000, -3px -2px 1px #000000, 0 0 25px #000000, 0 0 35px #000000, 0 0 35px #000000, 0 0 31px #FFFFFF, 0 0 31px #FFFFFF, 0 0 31px #FFFFFF;
+ */
+ background-color: #333;
+}
+.ttmlStyled a {
+ text-decoration: none;
+ color : #BBF;
+}
+.ttmlStyled a:visited{
+ color : #BBF;
+}