aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-08-16 10:48:35 +0200
committerChocobozzz <me@florianbigard.com>2018-08-16 10:48:35 +0200
commit3dfa84940273619ae00f11a5f419a5e4876b2f53 (patch)
treebd31beeb985a9696af90e15ff6b767c4a0da03d9
parent4f1f6f038389ce9cdf0c77dfccdc63efc6948101 (diff)
downloadPeerTube-3dfa84940273619ae00f11a5f419a5e4876b2f53.tar.gz
PeerTube-3dfa84940273619ae00f11a5f419a5e4876b2f53.tar.zst
PeerTube-3dfa84940273619ae00f11a5f419a5e4876b2f53.zip
Translate subtitle langs in player
-rw-r--r--client/src/app/core/server/server.service.ts4
-rw-r--r--client/src/app/shared/i18n/i18n-utils.ts7
-rw-r--r--client/src/app/shared/video-caption/video-caption.service.ts27
-rw-r--r--client/src/app/shared/video-import/video-import.service.ts3
-rw-r--r--client/src/app/shared/video/video.model.ts3
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts4
-rw-r--r--client/src/assets/player/peertube-player.ts34
-rw-r--r--client/src/standalone/videos/embed.ts11
-rwxr-xr-xscripts/build/client.sh8
-rw-r--r--shared/models/i18n/i18n.ts4
10 files changed, 73 insertions, 32 deletions
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index 52b50cbe8..6d886d2dd 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -7,8 +7,8 @@ import { getCompleteLocale, ServerConfig } from '../../../../../shared'
7import { About } from '../../../../../shared/models/server/about.model' 7import { About } from '../../../../../shared/models/server/about.model'
8import { environment } from '../../../environments/environment' 8import { environment } from '../../../environments/environment'
9import { VideoConstant } from '../../../../../shared/models/videos' 9import { VideoConstant } from '../../../../../shared/models/videos'
10import { isDefaultLocale } from '../../../../../shared/models/i18n' 10import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n'
11import { getDevLocale, isOnDevLocale, peertubeTranslate } from '@app/shared/i18n/i18n-utils' 11import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
12import { sortBy } from '@app/shared/misc/utils' 12import { sortBy } from '@app/shared/misc/utils'
13 13
14@Injectable() 14@Injectable()
diff --git a/client/src/app/shared/i18n/i18n-utils.ts b/client/src/app/shared/i18n/i18n-utils.ts
index 37180b930..1838dc752 100644
--- a/client/src/app/shared/i18n/i18n-utils.ts
+++ b/client/src/app/shared/i18n/i18n-utils.ts
@@ -1,9 +1,5 @@
1import { environment } from '../../../environments/environment' 1import { environment } from '../../../environments/environment'
2 2
3function peertubeTranslate (str: string, translations: { [ id: string ]: string }) {
4 return translations[str] ? translations[str] : str
5}
6
7function isOnDevLocale () { 3function isOnDevLocale () {
8 return environment.production === false && window.location.search === '?lang=fr' 4 return environment.production === false && window.location.search === '?lang=fr'
9} 5}
@@ -14,6 +10,5 @@ function getDevLocale () {
14 10
15export { 11export {
16 getDevLocale, 12 getDevLocale,
17 isOnDevLocale, 13 isOnDevLocale
18 peertubeTranslate
19} 14}
diff --git a/client/src/app/shared/video-caption/video-caption.service.ts b/client/src/app/shared/video-caption/video-caption.service.ts
index 9c29bc052..994882451 100644
--- a/client/src/app/shared/video-caption/video-caption.service.ts
+++ b/client/src/app/shared/video-caption/video-caption.service.ts
@@ -1,29 +1,44 @@
1import { catchError, map } from 'rxjs/operators' 1import { catchError, map, switchMap } from 'rxjs/operators'
2import { HttpClient } from '@angular/common/http' 2import { HttpClient } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { forkJoin, Observable, of } from 'rxjs' 4import { forkJoin, Observable, of } from 'rxjs'
5import { ResultList } from '../../../../../shared' 5import { peertubeTranslate, ResultList } from '../../../../../shared'
6import { RestExtractor, RestService } from '../rest' 6import { RestExtractor, RestService } from '../rest'
7import { VideoService } from '@app/shared/video/video.service' 7import { VideoService } from '@app/shared/video/video.service'
8import { objectToFormData, sortBy } from '@app/shared/misc/utils' 8import { objectToFormData, sortBy } from '@app/shared/misc/utils'
9import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' 9import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
10import { VideoCaption } from '../../../../../shared/models/videos/caption/video-caption.model' 10import { VideoCaption } from '../../../../../shared/models/videos/caption/video-caption.model'
11import { ServerService } from '@app/core'
11 12
12@Injectable() 13@Injectable()
13export class VideoCaptionService { 14export class VideoCaptionService {
14 constructor ( 15 constructor (
15 private authHttp: HttpClient, 16 private authHttp: HttpClient,
17 private serverService: ServerService,
16 private restService: RestService, 18 private restService: RestService,
17 private restExtractor: RestExtractor 19 private restExtractor: RestExtractor
18 ) {} 20 ) {}
19 21
20 listCaptions (videoId: number | string): Observable<ResultList<VideoCaption>> { 22 listCaptions (videoId: number | string): Observable<ResultList<VideoCaption>> {
21 return this.authHttp.get<ResultList<VideoCaption>>(VideoService.BASE_VIDEO_URL + videoId + '/captions') 23 return this.authHttp.get<ResultList<VideoCaption>>(VideoService.BASE_VIDEO_URL + videoId + '/captions')
22 .pipe(map(res => { 24 .pipe(
23 sortBy(res.data, 'language', 'label') 25 switchMap(captionsResult => {
26 return this.serverService.localeObservable
27 .pipe(map(translations => ({ captionsResult, translations })))
28 }),
29 map(({ captionsResult, translations }) => {
30 for (const c of captionsResult.data) {
31 c.language.label = peertubeTranslate(c.language.label, translations)
32 }
33
34 return captionsResult
35 }),
36 map(captionsResult => {
37 sortBy(captionsResult.data, 'language', 'label')
24 38
25 return res 39 return captionsResult
26 })) 40 })
41 )
27 .pipe(catchError(res => this.restExtractor.handleError(res))) 42 .pipe(catchError(res => this.restExtractor.handleError(res)))
28 } 43 }
29 44
diff --git a/client/src/app/shared/video-import/video-import.service.ts b/client/src/app/shared/video-import/video-import.service.ts
index fc34dbf2d..7ae66ddfc 100644
--- a/client/src/app/shared/video-import/video-import.service.ts
+++ b/client/src/app/shared/video-import/video-import.service.ts
@@ -2,7 +2,7 @@ import { catchError, map, switchMap } from 'rxjs/operators'
2import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { Observable } from 'rxjs' 4import { Observable } from 'rxjs'
5import { VideoImport } from '../../../../../shared' 5import { peertubeTranslate, VideoImport } from '../../../../../shared'
6import { environment } from '../../../environments/environment' 6import { environment } from '../../../environments/environment'
7import { RestExtractor, RestService } from '../rest' 7import { RestExtractor, RestService } from '../rest'
8import { VideoImportCreate, VideoUpdate } from '../../../../../shared/models/videos' 8import { VideoImportCreate, VideoUpdate } from '../../../../../shared/models/videos'
@@ -12,7 +12,6 @@ import { UserService } from '@app/shared/users/user.service'
12import { SortMeta } from 'primeng/components/common/sortmeta' 12import { SortMeta } from 'primeng/components/common/sortmeta'
13import { RestPagination } from '@app/shared/rest' 13import { RestPagination } from '@app/shared/rest'
14import { ServerService } from '@app/core' 14import { ServerService } from '@app/core'
15import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
16 15
17@Injectable() 16@Injectable()
18export class VideoImportService { 17export class VideoImportService {
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
index ec0afcccb..df8253301 100644
--- a/client/src/app/shared/video/video.model.ts
+++ b/client/src/app/shared/video/video.model.ts
@@ -3,9 +3,8 @@ import { Video as VideoServerModel, VideoPrivacy, VideoState } from '../../../..
3import { Avatar } from '../../../../../shared/models/avatars/avatar.model' 3import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
4import { VideoConstant } from '../../../../../shared/models/videos/video-constant.model' 4import { VideoConstant } from '../../../../../shared/models/videos/video-constant.model'
5import { getAbsoluteAPIUrl } from '../misc/utils' 5import { getAbsoluteAPIUrl } from '../misc/utils'
6import { ServerConfig } from '../../../../../shared/models' 6import { peertubeTranslate, ServerConfig } from '../../../../../shared/models'
7import { Actor } from '@app/shared/actor/actor.model' 7import { Actor } from '@app/shared/actor/actor.model'
8import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
9import { VideoScheduleUpdate } from '../../../../../shared/models/videos/video-schedule-update.model' 8import { VideoScheduleUpdate } from '../../../../../shared/models/videos/video-schedule-update.model'
10 9
11export class Video implements VideoServerModel { 10export class Video implements VideoServerModel {
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index d8230f172..5fba1b12d 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -22,7 +22,7 @@ import { VideoDownloadComponent } from './modal/video-download.component'
22import { VideoReportComponent } from './modal/video-report.component' 22import { VideoReportComponent } from './modal/video-report.component'
23import { VideoShareComponent } from './modal/video-share.component' 23import { VideoShareComponent } from './modal/video-share.component'
24import { VideoBlacklistComponent } from './modal/video-blacklist.component' 24import { VideoBlacklistComponent } from './modal/video-blacklist.component'
25import { addContextMenu, getVideojsOptions, loadLocale } from '../../../assets/player/peertube-player' 25import { addContextMenu, getVideojsOptions, loadLocaleInVideoJS } from '../../../assets/player/peertube-player'
26import { ServerService } from '@app/core' 26import { ServerService } from '@app/core'
27import { I18n } from '@ngx-translate/i18n-polyfill' 27import { I18n } from '@ngx-translate/i18n-polyfill'
28import { environment } from '../../../environments/environment' 28import { environment } from '../../../environments/environment'
@@ -411,7 +411,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
411 }) 411 })
412 412
413 if (this.videojsLocaleLoaded === false) { 413 if (this.videojsLocaleLoaded === false) {
414 await loadLocale(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId) 414 await loadLocaleInVideoJS(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId)
415 this.videojsLocaleLoaded = true 415 this.videojsLocaleLoaded = true
416 } 416 }
417 417
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts
index 1fca6a7d2..1b1ec7a68 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/assets/player/peertube-player.ts
@@ -174,18 +174,42 @@ function addContextMenu (player: any, videoEmbedUrl: string) {
174 }) 174 })
175} 175}
176 176
177function loadLocale (serverUrl: string, videojs: any, locale: string) { 177function loadLocaleInVideoJS (serverUrl: string, videojs: any, locale: string) {
178 const completeLocale = getCompleteLocale(locale) 178 const path = getLocalePath(serverUrl, locale)
179 // It is the default locale, nothing to translate
180 if (!path) return Promise.resolve(undefined)
179 181
180 if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return Promise.resolve(undefined) 182 const completeLocale = getCompleteLocale(locale)
181 183
182 return fetch(serverUrl + '/client/locales/' + completeLocale + '/player.json') 184 return fetch(path + '/player.json')
183 .then(res => res.json()) 185 .then(res => res.json())
184 .then(json => videojs.addLanguage(getShortLocale(completeLocale), json)) 186 .then(json => videojs.addLanguage(getShortLocale(completeLocale), json))
185} 187}
186 188
189function getServerTranslations (serverUrl: string, locale: string) {
190 const path = getLocalePath(serverUrl, locale)
191 // It is the default locale, nothing to translate
192 if (!path) return Promise.resolve(undefined)
193
194 return fetch(path + '/server.json')
195 .then(res => res.json())
196}
197
198// ############################################################################
199
187export { 200export {
188 loadLocale, 201 getServerTranslations,
202 loadLocaleInVideoJS,
189 getVideojsOptions, 203 getVideojsOptions,
190 addContextMenu 204 addContextMenu
191} 205}
206
207// ############################################################################
208
209function getLocalePath (serverUrl: string, locale: string) {
210 const completeLocale = getCompleteLocale(locale)
211
212 if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return undefined
213
214 return serverUrl + '/client/locales/' + completeLocale
215}
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 2aabb5fe8..ea3436c7c 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -20,8 +20,8 @@ import 'whatwg-fetch'
20import * as vjs from 'video.js' 20import * as vjs from 'video.js'
21import * as Channel from 'jschannel' 21import * as Channel from 'jschannel'
22 22
23import { ResultList, VideoDetails } from '../../../../shared' 23import { peertubeTranslate, ResultList, VideoDetails } from '../../../../shared'
24import { addContextMenu, getVideojsOptions, loadLocale } from '../../assets/player/peertube-player' 24import { addContextMenu, getServerTranslations, getVideojsOptions, loadLocaleInVideoJS } from '../../assets/player/peertube-player'
25import { PeerTubeResolution } from '../player/definitions' 25import { PeerTubeResolution } from '../player/definitions'
26import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' 26import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
27import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' 27import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
@@ -257,8 +257,9 @@ class PeerTubeEmbed {
257 const lastPart = urlParts[ urlParts.length - 1 ] 257 const lastPart = urlParts[ urlParts.length - 1 ]
258 const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ] 258 const videoId = lastPart.indexOf('?') === -1 ? lastPart : lastPart.split('?')[ 0 ]
259 259
260 await loadLocale(window.location.origin, vjs, navigator.language) 260 const [ , serverTranslations, videoResponse, captionsResponse ] = await Promise.all([
261 const [ videoResponse, captionsResponse ] = await Promise.all([ 261 loadLocaleInVideoJS(window.location.origin, vjs, navigator.language),
262 getServerTranslations(window.location.origin, navigator.language),
262 this.loadVideoInfo(videoId), 263 this.loadVideoInfo(videoId),
263 this.loadVideoCaptions(videoId) 264 this.loadVideoCaptions(videoId)
264 ]) 265 ])
@@ -274,7 +275,7 @@ class PeerTubeEmbed {
274 if (captionsResponse.ok) { 275 if (captionsResponse.ok) {
275 const { data } = (await captionsResponse.json()) as ResultList<VideoCaption> 276 const { data } = (await captionsResponse.json()) as ResultList<VideoCaption>
276 videoCaptions = data.map(c => ({ 277 videoCaptions = data.map(c => ({
277 label: c.language.label, 278 label: peertubeTranslate(c.language.label, serverTranslations),
278 language: c.language.id, 279 language: c.language.id,
279 src: window.location.origin + c.captionPath 280 src: window.location.origin + c.captionPath
280 })) 281 }))
diff --git a/scripts/build/client.sh b/scripts/build/client.sh
index 080454d07..3d1d0234e 100755
--- a/scripts/build/client.sh
+++ b/scripts/build/client.sh
@@ -30,8 +30,12 @@ post_build_hook
30 30
31# Don't build other languages if --light arg is provided 31# Don't build other languages if --light arg is provided
32if [ -z ${1+x} ] || [ "$1" != "--light" ]; then 32if [ -z ${1+x} ] || [ "$1" != "--light" ]; then
33 # Supported languages 33 if [ ! -z ${1+x} ] && [ "$1" == "--light-fr" ]; then
34 languages=("fr_FR" "eu_ES" "ca_ES" "cs_CZ" "eo" "zh_Hant_TW" "de_DE" "es_ES" "oc") 34 languages=("fr_FR")
35 else
36 # Supported languages
37 languages=("fr_FR" "eu_ES" "ca_ES" "cs_CZ" "eo" "zh_Hant_TW" "de_DE" "es_ES" "oc")
38 fi
35 39
36 for lang in "${languages[@]}"; do 40 for lang in "${languages[@]}"; do
37 # TODO: remove when the project will use runtime translations 41 # TODO: remove when the project will use runtime translations
diff --git a/shared/models/i18n/i18n.ts b/shared/models/i18n/i18n.ts
index 2530a1927..c5de972ac 100644
--- a/shared/models/i18n/i18n.ts
+++ b/shared/models/i18n/i18n.ts
@@ -36,6 +36,10 @@ export function isDefaultLocale (locale: string) {
36 return getCompleteLocale(locale) === getCompleteLocale(getDefaultLocale()) 36 return getCompleteLocale(locale) === getCompleteLocale(getDefaultLocale())
37} 37}
38 38
39export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) {
40 return translations && translations[str] ? translations[str] : str
41}
42
39const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l) 43const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l)
40export function is18nPath (path: string) { 44export function is18nPath (path: string) {
41 return possiblePaths.indexOf(path) !== -1 45 return possiblePaths.indexOf(path) !== -1