aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-06-06 16:46:42 +0200
committerChocobozzz <me@florianbigard.com>2018-06-06 16:48:41 +0200
commit7ce44a74a3b052190cfacd4bd5ee6b92cfc620ac (patch)
tree6f178426c165f9136eb08354efa4a06c24725f87 /client/src/app
parentf07d6385b4b46c3254898292a8a53ed415b8d49b (diff)
downloadPeerTube-7ce44a74a3b052190cfacd4bd5ee6b92cfc620ac.tar.gz
PeerTube-7ce44a74a3b052190cfacd4bd5ee6b92cfc620ac.tar.zst
PeerTube-7ce44a74a3b052190cfacd4bd5ee6b92cfc620ac.zip
Add server localization
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/core/server/server.service.ts76
-rw-r--r--client/src/app/shared/i18n/i18n-utils.ts7
-rw-r--r--client/src/app/shared/video/video-details.model.ts4
-rw-r--r--client/src/app/shared/video/video.model.ts8
-rw-r--r--client/src/app/shared/video/video.service.ts56
5 files changed, 102 insertions, 49 deletions
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index ccae5a151..56d33339e 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -1,17 +1,20 @@
1import { tap } from 'rxjs/operators' 1import { map, share, switchMap, tap } from 'rxjs/operators'
2import { HttpClient } from '@angular/common/http' 2import { HttpClient } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Inject, Injectable, LOCALE_ID } from '@angular/core'
4import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' 4import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
5import { ReplaySubject } from 'rxjs' 5import { Observable, ReplaySubject } from 'rxjs'
6import { ServerConfig } from '../../../../../shared' 6import { 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, VideoPrivacy } from '../../../../../shared/models/videos' 9import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
10import { buildFileLocale, getDefaultLocale } from '../../../../../shared/models/i18n'
11import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
10 12
11@Injectable() 13@Injectable()
12export class ServerService { 14export class ServerService {
13 private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/' 15 private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
14 private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' 16 private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
17 private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
15 private static CONFIG_LOCAL_STORAGE_KEY = 'server-config' 18 private static CONFIG_LOCAL_STORAGE_KEY = 'server-config'
16 19
17 configLoaded = new ReplaySubject<boolean>(1) 20 configLoaded = new ReplaySubject<boolean>(1)
@@ -19,6 +22,7 @@ export class ServerService {
19 videoCategoriesLoaded = new ReplaySubject<boolean>(1) 22 videoCategoriesLoaded = new ReplaySubject<boolean>(1)
20 videoLicencesLoaded = new ReplaySubject<boolean>(1) 23 videoLicencesLoaded = new ReplaySubject<boolean>(1)
21 videoLanguagesLoaded = new ReplaySubject<boolean>(1) 24 videoLanguagesLoaded = new ReplaySubject<boolean>(1)
25 localeObservable: Observable<any>
22 26
23 private config: ServerConfig = { 27 private config: ServerConfig = {
24 instance: { 28 instance: {
@@ -64,8 +68,12 @@ export class ServerService {
64 private videoLanguages: Array<VideoConstant<string>> = [] 68 private videoLanguages: Array<VideoConstant<string>> = []
65 private videoPrivacies: Array<VideoConstant<VideoPrivacy>> = [] 69 private videoPrivacies: Array<VideoConstant<VideoPrivacy>> = []
66 70
67 constructor (private http: HttpClient) { 71 constructor (
72 private http: HttpClient,
73 @Inject(LOCALE_ID) private localeId: string
74 ) {
68 this.loadConfigLocally() 75 this.loadConfigLocally()
76 this.loadServerLocale()
69 } 77 }
70 78
71 loadConfig () { 79 loadConfig () {
@@ -124,26 +132,46 @@ export class ServerService {
124 notifier: ReplaySubject<boolean>, 132 notifier: ReplaySubject<boolean>,
125 sort = false 133 sort = false
126 ) { 134 ) {
127 return this.http.get(ServerService.BASE_VIDEO_URL + attributeName) 135 this.localeObservable
128 .subscribe(data => { 136 .pipe(
129 Object.keys(data) 137 switchMap(translations => {
130 .forEach(dataKey => { 138 return this.http.get(ServerService.BASE_VIDEO_URL + attributeName)
131 hashToPopulate.push({ 139 .pipe(map(data => ({ data, translations })))
132 id: dataKey, 140 })
133 label: data[dataKey] 141 )
134 }) 142 .subscribe(({ data, translations }) => {
135 }) 143 Object.keys(data)
136 144 .forEach(dataKey => {
137 if (sort === true) { 145 const label = data[ dataKey ]
138 hashToPopulate.sort((a, b) => { 146
139 if (a.label < b.label) return -1 147 hashToPopulate.push({
140 if (a.label === b.label) return 0 148 id: dataKey,
141 return 1 149 label: peertubeTranslate(label, translations)
142 }) 150 })
143 } 151 })
144 152
145 notifier.next(true) 153 if (sort === true) {
146 }) 154 hashToPopulate.sort((a, b) => {
155 if (a.label < b.label) return -1
156 if (a.label === b.label) return 0
157 return 1
158 })
159 }
160
161 notifier.next(true)
162 })
163 }
164
165 private loadServerLocale () {
166 const fileLocale = buildFileLocale(environment.production === true ? this.localeId : 'fr')
167
168 // Default locale, nothing to translate
169 const defaultFileLocale = buildFileLocale(getDefaultLocale())
170 if (fileLocale === defaultFileLocale) return {}
171
172 this.localeObservable = this.http
173 .get(ServerService.BASE_LOCALE_URL + fileLocale + '/server.json')
174 .pipe(share())
147 } 175 }
148 176
149 private saveConfigLocally (config: ServerConfig) { 177 private saveConfigLocally (config: ServerConfig) {
diff --git a/client/src/app/shared/i18n/i18n-utils.ts b/client/src/app/shared/i18n/i18n-utils.ts
new file mode 100644
index 000000000..c1de51b7b
--- /dev/null
+++ b/client/src/app/shared/i18n/i18n-utils.ts
@@ -0,0 +1,7 @@
1function peertubeTranslate (str: string, translations: { [ id: string ]: string }) {
2 return translations[str] ? translations[str] : str
3}
4
5export {
6 peertubeTranslate
7}
diff --git a/client/src/app/shared/video/video-details.model.ts b/client/src/app/shared/video/video-details.model.ts
index 5fc55fca6..19c350ab3 100644
--- a/client/src/app/shared/video/video-details.model.ts
+++ b/client/src/app/shared/video/video-details.model.ts
@@ -15,8 +15,8 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
15 likesPercent: number 15 likesPercent: number
16 dislikesPercent: number 16 dislikesPercent: number
17 17
18 constructor (hash: VideoDetailsServerModel) { 18 constructor (hash: VideoDetailsServerModel, translations = {}) {
19 super(hash) 19 super(hash, translations)
20 20
21 this.descriptionPath = hash.descriptionPath 21 this.descriptionPath = hash.descriptionPath
22 this.files = hash.files 22 this.files = hash.files
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
index 48d562f9c..d37dc2c3e 100644
--- a/client/src/app/shared/video/video.model.ts
+++ b/client/src/app/shared/video/video.model.ts
@@ -5,6 +5,7 @@ import { VideoConstant } from '../../../../../shared/models/videos/video.model'
5import { getAbsoluteAPIUrl } from '../misc/utils' 5import { getAbsoluteAPIUrl } from '../misc/utils'
6import { ServerConfig } from '../../../../../shared/models' 6import { 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'
8 9
9export class Video implements VideoServerModel { 10export class Video implements VideoServerModel {
10 by: string 11 by: string
@@ -68,7 +69,7 @@ export class Video implements VideoServerModel {
68 minutes.toString() + ':' + secondsPadding + seconds.toString() 69 minutes.toString() + ':' + secondsPadding + seconds.toString()
69 } 70 }
70 71
71 constructor (hash: VideoServerModel) { 72 constructor (hash: VideoServerModel, translations = {}) {
72 const absoluteAPIUrl = getAbsoluteAPIUrl() 73 const absoluteAPIUrl = getAbsoluteAPIUrl()
73 74
74 this.createdAt = new Date(hash.createdAt.toString()) 75 this.createdAt = new Date(hash.createdAt.toString())
@@ -98,6 +99,11 @@ export class Video implements VideoServerModel {
98 99
99 this.by = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host) 100 this.by = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host)
100 this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) 101 this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account)
102
103 this.category.label = peertubeTranslate(this.category.label, translations)
104 this.licence.label = peertubeTranslate(this.licence.label, translations)
105 this.language.label = peertubeTranslate(this.language.label, translations)
106 this.privacy.label = peertubeTranslate(this.privacy.label, translations)
101 } 107 }
102 108
103 isVideoNSFWForUser (user: User, serverConfig: ServerConfig) { 109 isVideoNSFWForUser (user: User, serverConfig: ServerConfig) {
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts
index d1e32faeb..c607b7d6a 100644
--- a/client/src/app/shared/video/video.service.ts
+++ b/client/src/app/shared/video/video.service.ts
@@ -1,4 +1,4 @@
1import { catchError, map } from 'rxjs/operators' 1import { catchError, map, switchMap } from 'rxjs/operators'
2import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' 2import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { Observable } from 'rxjs' 4import { Observable } from 'rxjs'
@@ -24,6 +24,7 @@ import { Account } from '@app/shared/account/account.model'
24import { AccountService } from '@app/shared/account/account.service' 24import { AccountService } from '@app/shared/account/account.service'
25import { VideoChannel } from '../../../../../shared/models/videos' 25import { VideoChannel } from '../../../../../shared/models/videos'
26import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 26import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
27import { ServerService } from '@app/core'
27 28
28@Injectable() 29@Injectable()
29export class VideoService { 30export class VideoService {
@@ -33,7 +34,8 @@ export class VideoService {
33 constructor ( 34 constructor (
34 private authHttp: HttpClient, 35 private authHttp: HttpClient,
35 private restExtractor: RestExtractor, 36 private restExtractor: RestExtractor,
36 private restService: RestService 37 private restService: RestService,
38 private serverService: ServerService
37 ) {} 39 ) {}
38 40
39 getVideoViewUrl (uuid: string) { 41 getVideoViewUrl (uuid: string) {
@@ -41,9 +43,13 @@ export class VideoService {
41 } 43 }
42 44
43 getVideo (uuid: string): Observable<VideoDetails> { 45 getVideo (uuid: string): Observable<VideoDetails> {
44 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid) 46 return this.serverService.localeObservable
45 .pipe( 47 .pipe(
46 map(videoHash => new VideoDetails(videoHash)), 48 switchMap(translations => {
49 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
50 .pipe(map(videoHash => ({ videoHash, translations })))
51 }),
52 map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)),
47 catchError(res => this.restExtractor.handleError(res)) 53 catchError(res => this.restExtractor.handleError(res))
48 ) 54 )
49 } 55 }
@@ -102,9 +108,10 @@ export class VideoService {
102 let params = new HttpParams() 108 let params = new HttpParams()
103 params = this.restService.addRestGetParams(params, pagination, sort) 109 params = this.restService.addRestGetParams(params, pagination, sort)
104 110
105 return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params }) 111 return this.authHttp
112 .get<ResultList<Video>>(UserService.BASE_USERS_URL + '/me/videos', { params })
106 .pipe( 113 .pipe(
107 map(this.extractVideos), 114 switchMap(res => this.extractVideos(res)),
108 catchError(res => this.restExtractor.handleError(res)) 115 catchError(res => this.restExtractor.handleError(res))
109 ) 116 )
110 } 117 }
@@ -120,9 +127,9 @@ export class VideoService {
120 params = this.restService.addRestGetParams(params, pagination, sort) 127 params = this.restService.addRestGetParams(params, pagination, sort)
121 128
122 return this.authHttp 129 return this.authHttp
123 .get(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params }) 130 .get<ResultList<Video>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params })
124 .pipe( 131 .pipe(
125 map(this.extractVideos), 132 switchMap(res => this.extractVideos(res)),
126 catchError(res => this.restExtractor.handleError(res)) 133 catchError(res => this.restExtractor.handleError(res))
127 ) 134 )
128 } 135 }
@@ -138,9 +145,9 @@ export class VideoService {
138 params = this.restService.addRestGetParams(params, pagination, sort) 145 params = this.restService.addRestGetParams(params, pagination, sort)
139 146
140 return this.authHttp 147 return this.authHttp
141 .get(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params }) 148 .get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params })
142 .pipe( 149 .pipe(
143 map(this.extractVideos), 150 switchMap(res => this.extractVideos(res)),
144 catchError(res => this.restExtractor.handleError(res)) 151 catchError(res => this.restExtractor.handleError(res))
145 ) 152 )
146 } 153 }
@@ -160,9 +167,9 @@ export class VideoService {
160 } 167 }
161 168
162 return this.authHttp 169 return this.authHttp
163 .get(VideoService.BASE_VIDEO_URL, { params }) 170 .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params })
164 .pipe( 171 .pipe(
165 map(this.extractVideos), 172 switchMap(res => this.extractVideos(res)),
166 catchError(res => this.restExtractor.handleError(res)) 173 catchError(res => this.restExtractor.handleError(res))
167 ) 174 )
168 } 175 }
@@ -230,7 +237,7 @@ export class VideoService {
230 return this.authHttp 237 return this.authHttp
231 .get<ResultList<VideoServerModel>>(url, { params }) 238 .get<ResultList<VideoServerModel>>(url, { params })
232 .pipe( 239 .pipe(
233 map(this.extractVideos), 240 switchMap(res => this.extractVideos(res)),
234 catchError(res => this.restExtractor.handleError(res)) 241 catchError(res => this.restExtractor.handleError(res))
235 ) 242 )
236 } 243 }
@@ -287,14 +294,19 @@ export class VideoService {
287 } 294 }
288 295
289 private extractVideos (result: ResultList<VideoServerModel>) { 296 private extractVideos (result: ResultList<VideoServerModel>) {
290 const videosJson = result.data 297 return this.serverService.localeObservable
291 const totalVideos = result.total 298 .pipe(
292 const videos = [] 299 map(translations => {
293 300 const videosJson = result.data
294 for (const videoJson of videosJson) { 301 const totalVideos = result.total
295 videos.push(new Video(videoJson)) 302 const videos: Video[] = []
296 } 303
297 304 for (const videoJson of videosJson) {
298 return { videos, totalVideos } 305 videos.push(new Video(videoJson, translations))
306 }
307
308 return { videos, totalVideos }
309 })
310 )
299 } 311 }
300} 312}