]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Translate subtitle langs in player
authorChocobozzz <me@florianbigard.com>
Thu, 16 Aug 2018 08:48:35 +0000 (10:48 +0200)
committerChocobozzz <me@florianbigard.com>
Thu, 16 Aug 2018 08:48:35 +0000 (10:48 +0200)
client/src/app/core/server/server.service.ts
client/src/app/shared/i18n/i18n-utils.ts
client/src/app/shared/video-caption/video-caption.service.ts
client/src/app/shared/video-import/video-import.service.ts
client/src/app/shared/video/video.model.ts
client/src/app/videos/+video-watch/video-watch.component.ts
client/src/assets/player/peertube-player.ts
client/src/standalone/videos/embed.ts
scripts/build/client.sh
shared/models/i18n/i18n.ts

index 52b50cbe8a851346bff4d4407a8486b1ebbf1094..6d886d2ddd85717f691c7dcf70cd8c59a18995d6 100644 (file)
@@ -7,8 +7,8 @@ import { getCompleteLocale, ServerConfig } from '../../../../../shared'
 import { About } from '../../../../../shared/models/server/about.model'
 import { environment } from '../../../environments/environment'
 import { VideoConstant } from '../../../../../shared/models/videos'
-import { isDefaultLocale } from '../../../../../shared/models/i18n'
-import { getDevLocale, isOnDevLocale, peertubeTranslate } from '@app/shared/i18n/i18n-utils'
+import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n'
+import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
 import { sortBy } from '@app/shared/misc/utils'
 
 @Injectable()
index 37180b9300c7ea0a2cbafe4de658bb2682dfa109..1838dc75226b4c5ff4279aa8fc9799e42ccfa9b1 100644 (file)
@@ -1,9 +1,5 @@
 import { environment } from '../../../environments/environment'
 
-function peertubeTranslate (str: string, translations: { [ id: string ]: string }) {
-  return translations[str] ? translations[str] : str
-}
-
 function isOnDevLocale () {
   return environment.production === false && window.location.search === '?lang=fr'
 }
@@ -14,6 +10,5 @@ function getDevLocale () {
 
 export {
   getDevLocale,
-  isOnDevLocale,
-  peertubeTranslate
+  isOnDevLocale
 }
index 9c29bc05208b8e9bd99c068240b475a91f1bc676..994882451b543d798705c4b27eddd26069bd59ca 100644 (file)
@@ -1,29 +1,44 @@
-import { catchError, map } from 'rxjs/operators'
+import { catchError, map, switchMap } from 'rxjs/operators'
 import { HttpClient } from '@angular/common/http'
 import { Injectable } from '@angular/core'
 import { forkJoin, Observable, of } from 'rxjs'
-import { ResultList } from '../../../../../shared'
+import { peertubeTranslate, ResultList } from '../../../../../shared'
 import { RestExtractor, RestService } from '../rest'
 import { VideoService } from '@app/shared/video/video.service'
 import { objectToFormData, sortBy } from '@app/shared/misc/utils'
 import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
 import { VideoCaption } from '../../../../../shared/models/videos/caption/video-caption.model'
+import { ServerService } from '@app/core'
 
 @Injectable()
 export class VideoCaptionService {
   constructor (
     private authHttp: HttpClient,
+    private serverService: ServerService,
     private restService: RestService,
     private restExtractor: RestExtractor
   ) {}
 
   listCaptions (videoId: number | string): Observable<ResultList<VideoCaption>> {
     return this.authHttp.get<ResultList<VideoCaption>>(VideoService.BASE_VIDEO_URL + videoId + '/captions')
-               .pipe(map(res => {
-                 sortBy(res.data, 'language', 'label')
+               .pipe(
+                 switchMap(captionsResult => {
+                   return this.serverService.localeObservable
+                     .pipe(map(translations => ({ captionsResult, translations })))
+                 }),
+                 map(({ captionsResult, translations }) => {
+                   for (const c of captionsResult.data) {
+                     c.language.label = peertubeTranslate(c.language.label, translations)
+                   }
+
+                   return captionsResult
+                 }),
+                 map(captionsResult => {
+                   sortBy(captionsResult.data, 'language', 'label')
 
-                 return res
-               }))
+                   return captionsResult
+                 })
+               )
                .pipe(catchError(res => this.restExtractor.handleError(res)))
   }
 
index fc34dbf2d33ca748f3273f23484283eac4aba5c8..7ae66ddfcdf23a447e1fcb3ab982cda5039b57c7 100644 (file)
@@ -2,7 +2,7 @@ import { catchError, map, switchMap } from 'rxjs/operators'
 import { HttpClient, HttpParams } from '@angular/common/http'
 import { Injectable } from '@angular/core'
 import { Observable } from 'rxjs'
-import { VideoImport } from '../../../../../shared'
+import { peertubeTranslate, VideoImport } from '../../../../../shared'
 import { environment } from '../../../environments/environment'
 import { RestExtractor, RestService } from '../rest'
 import { VideoImportCreate, VideoUpdate } from '../../../../../shared/models/videos'
@@ -12,7 +12,6 @@ import { UserService } from '@app/shared/users/user.service'
 import { SortMeta } from 'primeng/components/common/sortmeta'
 import { RestPagination } from '@app/shared/rest'
 import { ServerService } from '@app/core'
-import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
 
 @Injectable()
 export class VideoImportService {
index ec0afcccb5360b1a036101525b25853236a18e7b..df825330173ed45e92c6fbb998d16ca4b5bf0283 100644 (file)
@@ -3,9 +3,8 @@ import { Video as VideoServerModel, VideoPrivacy, VideoState } from '../../../..
 import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
 import { VideoConstant } from '../../../../../shared/models/videos/video-constant.model'
 import { getAbsoluteAPIUrl } from '../misc/utils'
-import { ServerConfig } from '../../../../../shared/models'
+import { peertubeTranslate, ServerConfig } from '../../../../../shared/models'
 import { Actor } from '@app/shared/actor/actor.model'
-import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
 import { VideoScheduleUpdate } from '../../../../../shared/models/videos/video-schedule-update.model'
 
 export class Video implements VideoServerModel {
index d8230f172b371d0e3c2e815106c332b8488e007c..5fba1b12d4204826aa851ce4abb472a636fd3c2d 100644 (file)
@@ -22,7 +22,7 @@ import { VideoDownloadComponent } from './modal/video-download.component'
 import { VideoReportComponent } from './modal/video-report.component'
 import { VideoShareComponent } from './modal/video-share.component'
 import { VideoBlacklistComponent } from './modal/video-blacklist.component'
-import { addContextMenu, getVideojsOptions, loadLocale } from '../../../assets/player/peertube-player'
+import { addContextMenu, getVideojsOptions, loadLocaleInVideoJS } from '../../../assets/player/peertube-player'
 import { ServerService } from '@app/core'
 import { I18n } from '@ngx-translate/i18n-polyfill'
 import { environment } from '../../../environments/environment'
@@ -411,7 +411,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
     })
 
     if (this.videojsLocaleLoaded === false) {
-      await loadLocale(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId)
+      await loadLocaleInVideoJS(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId)
       this.videojsLocaleLoaded = true
     }
 
index 1fca6a7d2c38e0039d23aa1795eb435ac565cbca..1b1ec7a68933fde60690961683a03c63d0a1d48e 100644 (file)
@@ -174,18 +174,42 @@ function addContextMenu (player: any, videoEmbedUrl: string) {
   })
 }
 
-function loadLocale (serverUrl: string, videojs: any, locale: string) {
-  const completeLocale = getCompleteLocale(locale)
+function loadLocaleInVideoJS (serverUrl: string, videojs: any, locale: string) {
+  const path = getLocalePath(serverUrl, locale)
+  // It is the default locale, nothing to translate
+  if (!path) return Promise.resolve(undefined)
 
-  if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return Promise.resolve(undefined)
+  const completeLocale = getCompleteLocale(locale)
 
-  return fetch(serverUrl + '/client/locales/' + completeLocale + '/player.json')
+  return fetch(path + '/player.json')
     .then(res => res.json())
     .then(json => videojs.addLanguage(getShortLocale(completeLocale), json))
 }
 
+function getServerTranslations (serverUrl: string, locale: string) {
+  const path = getLocalePath(serverUrl, locale)
+  // It is the default locale, nothing to translate
+  if (!path) return Promise.resolve(undefined)
+
+  return fetch(path + '/server.json')
+    .then(res => res.json())
+}
+
+// ############################################################################
+
 export {
-  loadLocale,
+  getServerTranslations,
+  loadLocaleInVideoJS,
   getVideojsOptions,
   addContextMenu
 }
+
+// ############################################################################
+
+function getLocalePath (serverUrl: string, locale: string) {
+  const completeLocale = getCompleteLocale(locale)
+
+  if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return undefined
+
+  return serverUrl + '/client/locales/' + completeLocale
+}
index 2aabb5fe8ee526e2d852ac53173e56e2e93e9c94..ea3436c7c847b026b63b7a2e9bf8e5d8e0120a5b 100644 (file)
@@ -20,8 +20,8 @@ import 'whatwg-fetch'
 import * as vjs from 'video.js'
 import * as Channel from 'jschannel'
 
-import { ResultList, VideoDetails } from '../../../../shared'
-import { addContextMenu, getVideojsOptions, loadLocale } from '../../assets/player/peertube-player'
+import { peertubeTranslate, ResultList, VideoDetails } from '../../../../shared'
+import { addContextMenu, getServerTranslations, getVideojsOptions, loadLocaleInVideoJS } from '../../assets/player/peertube-player'
 import { PeerTubeResolution } from '../player/definitions'
 import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
 import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
@@ -257,8 +257,9 @@ class PeerTubeEmbed {
     const lastPart = urlParts[ urlParts.length - 1 ]
     const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ]
 
-    await loadLocale(window.location.origin, vjs, navigator.language)
-    const [ videoResponse, captionsResponse ] = await Promise.all([
+    const [ , serverTranslations, videoResponse, captionsResponse ] = await Promise.all([
+      loadLocaleInVideoJS(window.location.origin, vjs, navigator.language),
+      getServerTranslations(window.location.origin, navigator.language),
       this.loadVideoInfo(videoId),
       this.loadVideoCaptions(videoId)
     ])
@@ -274,7 +275,7 @@ class PeerTubeEmbed {
     if (captionsResponse.ok) {
       const { data } = (await captionsResponse.json()) as ResultList<VideoCaption>
       videoCaptions = data.map(c => ({
-        label: c.language.label,
+        label: peertubeTranslate(c.language.label, serverTranslations),
         language: c.language.id,
         src: window.location.origin + c.captionPath
       }))
index 080454d070c0065b5697b9a457260ea6ffdb3e4e..3d1d0234e79d84ec40f803ca9649f442efa31d83 100755 (executable)
@@ -30,8 +30,12 @@ post_build_hook
 
 # Don't build other languages if --light arg is provided
 if [ -z ${1+x} ] || [ "$1" != "--light" ]; then
-    # Supported languages
-    languages=("fr_FR" "eu_ES" "ca_ES" "cs_CZ" "eo" "zh_Hant_TW" "de_DE" "es_ES" "oc")
+    if [ ! -z ${1+x} ] && [ "$1" == "--light-fr" ]; then
+        languages=("fr_FR")
+    else
+        # Supported languages
+        languages=("fr_FR" "eu_ES" "ca_ES" "cs_CZ" "eo" "zh_Hant_TW" "de_DE" "es_ES" "oc")
+    fi
 
     for lang in "${languages[@]}"; do
         # TODO: remove when the project will use runtime translations
index 2530a19272dc953fc8817bae26ef1c1624ef0b7d..c5de972ac685927b0d85463176863d872fcb333a 100644 (file)
@@ -36,6 +36,10 @@ export function isDefaultLocale (locale: string) {
   return getCompleteLocale(locale) === getCompleteLocale(getDefaultLocale())
 }
 
+export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) {
+  return translations && translations[str] ? translations[str] : str
+}
+
 const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l)
 export function is18nPath (path: string) {
   return possiblePaths.indexOf(path) !== -1