Add server localization
authorChocobozzz <me@florianbigard.com>
Wed, 6 Jun 2018 14:46:42 +0000 (16:46 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 6 Jun 2018 14:48:41 +0000 (16:48 +0200)
12 files changed:
client/src/app/core/server/server.service.ts
client/src/app/shared/i18n/i18n-utils.ts [new file with mode: 0644]
client/src/app/shared/video/video-details.model.ts
client/src/app/shared/video/video.model.ts
client/src/app/shared/video/video.service.ts
client/src/locale/source/server_en_US.xml [new file with mode: 0644]
client/src/locale/target/player_fr.xml [deleted file]
client/src/locale/target/server_fr.json [new file with mode: 0644]
scripts/i18n/create-custom-files.ts
scripts/i18n/xliff2json.ts
server/controllers/client.ts
server/initializers/constants.ts

index ccae5a151fbc97bf4b929981431421da361d6e0c..56d33339ebdf0e663df98506efa92ce0ac7c04e9 100644 (file)
@@ -1,17 +1,20 @@
-import { tap } from 'rxjs/operators'
+import { map, share, switchMap, tap } from 'rxjs/operators'
 import { HttpClient } from '@angular/common/http'
-import { Injectable } from '@angular/core'
+import { Inject, Injectable, LOCALE_ID } from '@angular/core'
 import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
-import { ReplaySubject } from 'rxjs'
+import { Observable, ReplaySubject } from 'rxjs'
 import { ServerConfig } from '../../../../../shared'
 import { About } from '../../../../../shared/models/server/about.model'
 import { environment } from '../../../environments/environment'
 import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
+import { buildFileLocale, getDefaultLocale } from '../../../../../shared/models/i18n'
+import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
 
 @Injectable()
 export class ServerService {
   private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
   private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
+  private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
   private static CONFIG_LOCAL_STORAGE_KEY = 'server-config'
 
   configLoaded = new ReplaySubject<boolean>(1)
@@ -19,6 +22,7 @@ export class ServerService {
   videoCategoriesLoaded = new ReplaySubject<boolean>(1)
   videoLicencesLoaded = new ReplaySubject<boolean>(1)
   videoLanguagesLoaded = new ReplaySubject<boolean>(1)
+  localeObservable: Observable<any>
 
   private config: ServerConfig = {
     instance: {
@@ -64,8 +68,12 @@ export class ServerService {
   private videoLanguages: Array<VideoConstant<string>> = []
   private videoPrivacies: Array<VideoConstant<VideoPrivacy>> = []
 
-  constructor (private http: HttpClient) {
+  constructor (
+    private http: HttpClient,
+    @Inject(LOCALE_ID) private localeId: string
+  ) {
     this.loadConfigLocally()
+    this.loadServerLocale()
   }
 
   loadConfig () {
@@ -124,26 +132,46 @@ export class ServerService {
     notifier: ReplaySubject<boolean>,
     sort = false
   ) {
-    return this.http.get(ServerService.BASE_VIDEO_URL + attributeName)
-       .subscribe(data => {
-         Object.keys(data)
-               .forEach(dataKey => {
-                 hashToPopulate.push({
-                   id: dataKey,
-                   label: data[dataKey]
-                 })
-               })
-
-         if (sort === true) {
-           hashToPopulate.sort((a, b) => {
-             if (a.label < b.label) return -1
-             if (a.label === b.label) return 0
-             return 1
-           })
-         }
-
-         notifier.next(true)
-       })
+    this.localeObservable
+        .pipe(
+          switchMap(translations => {
+            return this.http.get(ServerService.BASE_VIDEO_URL + attributeName)
+                       .pipe(map(data => ({ data, translations })))
+          })
+        )
+        .subscribe(({ data, translations }) => {
+          Object.keys(data)
+                .forEach(dataKey => {
+                  const label = data[ dataKey ]
+
+                  hashToPopulate.push({
+                    id: dataKey,
+                    label: peertubeTranslate(label, translations)
+                  })
+                })
+
+          if (sort === true) {
+            hashToPopulate.sort((a, b) => {
+              if (a.label < b.label) return -1
+              if (a.label === b.label) return 0
+              return 1
+            })
+          }
+
+          notifier.next(true)
+        })
+  }
+
+  private loadServerLocale () {
+    const fileLocale = buildFileLocale(environment.production === true ? this.localeId : 'fr')
+
+    // Default locale, nothing to translate
+    const defaultFileLocale = buildFileLocale(getDefaultLocale())
+    if (fileLocale === defaultFileLocale) return {}
+
+    this.localeObservable = this.http
+                                  .get(ServerService.BASE_LOCALE_URL + fileLocale + '/server.json')
+                                  .pipe(share())
   }
 
   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 (file)
index 0000000..c1de51b
--- /dev/null
@@ -0,0 +1,7 @@
+function peertubeTranslate (str: string, translations: { [ id: string ]: string }) {
+  return translations[str] ? translations[str] : str
+}
+
+export {
+  peertubeTranslate
+}
index 5fc55fca60de1f68caa6919b4ddb9a9fd318c30c..19c350ab34fdcc146d80e0334587db944df8661f 100644 (file)
@@ -15,8 +15,8 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
   likesPercent: number
   dislikesPercent: number
 
-  constructor (hash: VideoDetailsServerModel) {
-    super(hash)
+  constructor (hash: VideoDetailsServerModel, translations = {}) {
+    super(hash, translations)
 
     this.descriptionPath = hash.descriptionPath
     this.files = hash.files
index 48d562f9c863fe8d88ce8423b7951f29d6726e21..d37dc2c3ef969d431f962278b7e0d2045ca83109 100644 (file)
@@ -5,6 +5,7 @@ import { VideoConstant } from '../../../../../shared/models/videos/video.model'
 import { getAbsoluteAPIUrl } from '../misc/utils'
 import { ServerConfig } from '../../../../../shared/models'
 import { Actor } from '@app/shared/actor/actor.model'
+import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
 
 export class Video implements VideoServerModel {
   by: string
@@ -68,7 +69,7 @@ export class Video implements VideoServerModel {
         minutes.toString() + ':' + secondsPadding + seconds.toString()
   }
 
-  constructor (hash: VideoServerModel) {
+  constructor (hash: VideoServerModel, translations = {}) {
     const absoluteAPIUrl = getAbsoluteAPIUrl()
 
     this.createdAt = new Date(hash.createdAt.toString())
@@ -98,6 +99,11 @@ export class Video implements VideoServerModel {
 
     this.by = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host)
     this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account)
+
+    this.category.label = peertubeTranslate(this.category.label, translations)
+    this.licence.label = peertubeTranslate(this.licence.label, translations)
+    this.language.label = peertubeTranslate(this.language.label, translations)
+    this.privacy.label = peertubeTranslate(this.privacy.label, translations)
   }
 
   isVideoNSFWForUser (user: User, serverConfig: ServerConfig) {
index d1e32faebd55719de1a4131ba7bb0f149bb302aa..c607b7d6a70ae0d69fb0d38a81718a2351da22d8 100644 (file)
@@ -1,4 +1,4 @@
-import { catchError, map } from 'rxjs/operators'
+import { catchError, map, switchMap } from 'rxjs/operators'
 import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
 import { Injectable } from '@angular/core'
 import { Observable } from 'rxjs'
@@ -24,6 +24,7 @@ import { Account } from '@app/shared/account/account.model'
 import { AccountService } from '@app/shared/account/account.service'
 import { VideoChannel } from '../../../../../shared/models/videos'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
+import { ServerService } from '@app/core'
 
 @Injectable()
 export class VideoService {
@@ -33,7 +34,8 @@ export class VideoService {
   constructor (
     private authHttp: HttpClient,
     private restExtractor: RestExtractor,
-    private restService: RestService
+    private restService: RestService,
+    private serverService: ServerService
   ) {}
 
   getVideoViewUrl (uuid: string) {
@@ -41,9 +43,13 @@ export class VideoService {
   }
 
   getVideo (uuid: string): Observable<VideoDetails> {
-    return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
+    return this.serverService.localeObservable
                .pipe(
-                 map(videoHash => new VideoDetails(videoHash)),
+                 switchMap(translations => {
+                  return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
+                     .pipe(map(videoHash => ({ videoHash, translations })))
+                 }),
+                 map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)),
                  catchError(res => this.restExtractor.handleError(res))
                )
   }
@@ -102,9 +108,10 @@ export class VideoService {
     let params = new HttpParams()
     params = this.restService.addRestGetParams(params, pagination, sort)
 
-    return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params })
+    return this.authHttp
+               .get<ResultList<Video>>(UserService.BASE_USERS_URL + '/me/videos', { params })
                .pipe(
-                 map(this.extractVideos),
+                 switchMap(res => this.extractVideos(res)),
                  catchError(res => this.restExtractor.handleError(res))
                )
   }
@@ -120,9 +127,9 @@ export class VideoService {
     params = this.restService.addRestGetParams(params, pagination, sort)
 
     return this.authHttp
-               .get(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params })
+               .get<ResultList<Video>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params })
                .pipe(
-                 map(this.extractVideos),
+                 switchMap(res => this.extractVideos(res)),
                  catchError(res => this.restExtractor.handleError(res))
                )
   }
@@ -138,9 +145,9 @@ export class VideoService {
     params = this.restService.addRestGetParams(params, pagination, sort)
 
     return this.authHttp
-               .get(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params })
+               .get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params })
                .pipe(
-                 map(this.extractVideos),
+                 switchMap(res => this.extractVideos(res)),
                  catchError(res => this.restExtractor.handleError(res))
                )
   }
@@ -160,9 +167,9 @@ export class VideoService {
     }
 
     return this.authHttp
-               .get(VideoService.BASE_VIDEO_URL, { params })
+               .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params })
                .pipe(
-                 map(this.extractVideos),
+                 switchMap(res => this.extractVideos(res)),
                  catchError(res => this.restExtractor.handleError(res))
                )
   }
@@ -230,7 +237,7 @@ export class VideoService {
     return this.authHttp
                .get<ResultList<VideoServerModel>>(url, { params })
                .pipe(
-                 map(this.extractVideos),
+                 switchMap(res => this.extractVideos(res)),
                  catchError(res => this.restExtractor.handleError(res))
                )
   }
@@ -287,14 +294,19 @@ export class VideoService {
   }
 
   private extractVideos (result: ResultList<VideoServerModel>) {
-    const videosJson = result.data
-    const totalVideos = result.total
-    const videos = []
-
-    for (const videoJson of videosJson) {
-      videos.push(new Video(videoJson))
-    }
-
-    return { videos, totalVideos }
+    return this.serverService.localeObservable
+      .pipe(
+        map(translations => {
+          const videosJson = result.data
+          const totalVideos = result.total
+          const videos: Video[] = []
+
+          for (const videoJson of videosJson) {
+            videos.push(new Video(videoJson, translations))
+          }
+
+          return { videos, totalVideos }
+        })
+      )
   }
 }
diff --git a/client/src/locale/source/server_en_US.xml b/client/src/locale/source/server_en_US.xml
new file mode 100644 (file)
index 0000000..dab91f9
--- /dev/null
@@ -0,0 +1,878 @@
+<xliff xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd" xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
+  <file original="namespace1" datatype="plaintext" source-language="undefined" target-language="undefined">
+    <body>
+      <trans-unit id="Music">
+        <source>Music</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Films">
+        <source>Films</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Vehicles">
+        <source>Vehicles</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Art">
+        <source>Art</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sports">
+        <source>Sports</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Travels">
+        <source>Travels</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Gaming">
+        <source>Gaming</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="People">
+        <source>People</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Comedy">
+        <source>Comedy</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Entertainment">
+        <source>Entertainment</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="News">
+        <source>News</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="How To">
+        <source>How To</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Education">
+        <source>Education</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Activism">
+        <source>Activism</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Science &amp; Technology">
+        <source>Science &amp; Technology</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Animals">
+        <source>Animals</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kids">
+        <source>Kids</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Food">
+        <source>Food</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Attribution">
+        <source>Attribution</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Attribution - Share Alike">
+        <source>Attribution - Share Alike</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Attribution - No Derivatives">
+        <source>Attribution - No Derivatives</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Attribution - Non Commercial">
+        <source>Attribution - Non Commercial</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Attribution - Non Commercial - Share Alike">
+        <source>Attribution - Non Commercial - Share Alike</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Attribution - Non Commercial - No Derivatives">
+        <source>Attribution - Non Commercial - No Derivatives</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Public Domain Dedication">
+        <source>Public Domain Dedication</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Public">
+        <source>Public</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Unlisted">
+        <source>Unlisted</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Private">
+        <source>Private</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Afar">
+        <source>Afar</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Abkhazian">
+        <source>Abkhazian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Afrikaans">
+        <source>Afrikaans</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Akan">
+        <source>Akan</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Amharic">
+        <source>Amharic</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Arabic">
+        <source>Arabic</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Aragonese">
+        <source>Aragonese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="American Sign Language">
+        <source>American Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Assamese">
+        <source>Assamese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Avaric">
+        <source>Avaric</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Aymara">
+        <source>Aymara</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Azerbaijani">
+        <source>Azerbaijani</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Bashkir">
+        <source>Bashkir</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Bambara">
+        <source>Bambara</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Belarusian">
+        <source>Belarusian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Bengali">
+        <source>Bengali</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="British Sign Language">
+        <source>British Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Bislama">
+        <source>Bislama</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tibetan">
+        <source>Tibetan</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Bosnian">
+        <source>Bosnian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Breton">
+        <source>Breton</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Bulgarian">
+        <source>Bulgarian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Brazilian Sign Language">
+        <source>Brazilian Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Catalan">
+        <source>Catalan</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Czech">
+        <source>Czech</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Chamorro">
+        <source>Chamorro</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Chechen">
+        <source>Chechen</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Chuvash">
+        <source>Chuvash</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Cornish">
+        <source>Cornish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Corsican">
+        <source>Corsican</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Cree">
+        <source>Cree</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Czech Sign Language">
+        <source>Czech Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Chinese Sign Language">
+        <source>Chinese Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Welsh">
+        <source>Welsh</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Danish">
+        <source>Danish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="German">
+        <source>German</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Dhivehi">
+        <source>Dhivehi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Danish Sign Language">
+        <source>Danish Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Dzongkha">
+        <source>Dzongkha</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Modern Greek (1453-)">
+        <source>Modern Greek (1453-)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="English">
+        <source>English</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Estonian">
+        <source>Estonian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Basque">
+        <source>Basque</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Ewe">
+        <source>Ewe</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Faroese">
+        <source>Faroese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Persian">
+        <source>Persian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Fijian">
+        <source>Fijian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Finnish">
+        <source>Finnish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="French">
+        <source>French</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Western Frisian">
+        <source>Western Frisian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="French Sign Language">
+        <source>French Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Fulah">
+        <source>Fulah</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Scottish Gaelic">
+        <source>Scottish Gaelic</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Irish">
+        <source>Irish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Galician">
+        <source>Galician</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Manx">
+        <source>Manx</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Guarani">
+        <source>Guarani</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="German Sign Language">
+        <source>German Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Gujarati">
+        <source>Gujarati</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Haitian">
+        <source>Haitian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Hausa">
+        <source>Hausa</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Serbo-Croatian">
+        <source>Serbo-Croatian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Hebrew">
+        <source>Hebrew</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Herero">
+        <source>Herero</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Hindi">
+        <source>Hindi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Hiri Motu">
+        <source>Hiri Motu</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Croatian">
+        <source>Croatian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Hungarian">
+        <source>Hungarian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Armenian">
+        <source>Armenian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Igbo">
+        <source>Igbo</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sichuan Yi">
+        <source>Sichuan Yi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Inuktitut">
+        <source>Inuktitut</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Indonesian">
+        <source>Indonesian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Inupiaq">
+        <source>Inupiaq</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Icelandic">
+        <source>Icelandic</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Italian">
+        <source>Italian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Javanese">
+        <source>Javanese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Japanese">
+        <source>Japanese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Japanese Sign Language">
+        <source>Japanese Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kalaallisut">
+        <source>Kalaallisut</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kannada">
+        <source>Kannada</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kashmiri">
+        <source>Kashmiri</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Georgian">
+        <source>Georgian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kanuri">
+        <source>Kanuri</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kazakh">
+        <source>Kazakh</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Khmer">
+        <source>Khmer</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kikuyu">
+        <source>Kikuyu</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kinyarwanda">
+        <source>Kinyarwanda</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kirghiz">
+        <source>Kirghiz</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Komi">
+        <source>Komi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kongo">
+        <source>Kongo</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Korean">
+        <source>Korean</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kuanyama">
+        <source>Kuanyama</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Kurdish">
+        <source>Kurdish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Lao">
+        <source>Lao</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Latvian">
+        <source>Latvian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Limburgan">
+        <source>Limburgan</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Lingala">
+        <source>Lingala</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Lithuanian">
+        <source>Lithuanian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Luxembourgish">
+        <source>Luxembourgish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Luba-Katanga">
+        <source>Luba-Katanga</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Ganda">
+        <source>Ganda</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Marshallese">
+        <source>Marshallese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Malayalam">
+        <source>Malayalam</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Marathi">
+        <source>Marathi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Macedonian">
+        <source>Macedonian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Malagasy">
+        <source>Malagasy</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Maltese">
+        <source>Maltese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Mongolian">
+        <source>Mongolian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Maori">
+        <source>Maori</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Malay (macrolanguage)">
+        <source>Malay (macrolanguage)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Burmese">
+        <source>Burmese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Nauru">
+        <source>Nauru</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Navajo">
+        <source>Navajo</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="South Ndebele">
+        <source>South Ndebele</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="North Ndebele">
+        <source>North Ndebele</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Ndonga">
+        <source>Ndonga</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Nepali (macrolanguage)">
+        <source>Nepali (macrolanguage)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Dutch">
+        <source>Dutch</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Norwegian Nynorsk">
+        <source>Norwegian Nynorsk</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Norwegian Bokmål">
+        <source>Norwegian Bokmål</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Norwegian">
+        <source>Norwegian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Nyanja">
+        <source>Nyanja</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Occitan (post 1500)">
+        <source>Occitan (post 1500)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Ojibwa">
+        <source>Ojibwa</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Oriya (macrolanguage)">
+        <source>Oriya (macrolanguage)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Oromo">
+        <source>Oromo</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Ossetian">
+        <source>Ossetian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Panjabi">
+        <source>Panjabi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Pakistan Sign Language">
+        <source>Pakistan Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Polish">
+        <source>Polish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Portuguese">
+        <source>Portuguese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Pushto">
+        <source>Pushto</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Quechua">
+        <source>Quechua</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Romansh">
+        <source>Romansh</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Romanian">
+        <source>Romanian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Russian Sign Language">
+        <source>Russian Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Rundi">
+        <source>Rundi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Russian">
+        <source>Russian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sango">
+        <source>Sango</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Saudi Arabian Sign Language">
+        <source>Saudi Arabian Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="South African Sign Language">
+        <source>South African Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sinhala">
+        <source>Sinhala</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Slovak">
+        <source>Slovak</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Slovenian">
+        <source>Slovenian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Northern Sami">
+        <source>Northern Sami</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Samoan">
+        <source>Samoan</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Shona">
+        <source>Shona</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sindhi">
+        <source>Sindhi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Somali">
+        <source>Somali</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Southern Sotho">
+        <source>Southern Sotho</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Spanish">
+        <source>Spanish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Albanian">
+        <source>Albanian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sardinian">
+        <source>Sardinian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Serbian">
+        <source>Serbian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Swati">
+        <source>Swati</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Sundanese">
+        <source>Sundanese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Swahili (macrolanguage)">
+        <source>Swahili (macrolanguage)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Swedish">
+        <source>Swedish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Swedish Sign Language">
+        <source>Swedish Sign Language</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tahitian">
+        <source>Tahitian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tamil">
+        <source>Tamil</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tatar">
+        <source>Tatar</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Telugu">
+        <source>Telugu</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tajik">
+        <source>Tajik</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tagalog">
+        <source>Tagalog</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Thai">
+        <source>Thai</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tigrinya">
+        <source>Tigrinya</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tonga (Tonga Islands)">
+        <source>Tonga (Tonga Islands)</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tswana">
+        <source>Tswana</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Tsonga">
+        <source>Tsonga</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Turkmen">
+        <source>Turkmen</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Turkish">
+        <source>Turkish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Twi">
+        <source>Twi</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Uighur">
+        <source>Uighur</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Ukrainian">
+        <source>Ukrainian</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Urdu">
+        <source>Urdu</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Uzbek">
+        <source>Uzbek</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Venda">
+        <source>Venda</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Vietnamese">
+        <source>Vietnamese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Walloon">
+        <source>Walloon</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Wolof">
+        <source>Wolof</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Xhosa">
+        <source>Xhosa</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Yiddish">
+        <source>Yiddish</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Yoruba">
+        <source>Yoruba</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Zhuang">
+        <source>Zhuang</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Chinese">
+        <source>Chinese</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Zulu">
+        <source>Zulu</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Misc">
+        <source>Misc</source>
+        <target>undefined</target>
+      </trans-unit>
+      <trans-unit id="Unknown">
+        <source>Unknown</source>
+        <target>undefined</target>
+      </trans-unit>
+    </body>
+  </file>
+</xliff>
\ No newline at end of file
diff --git a/client/src/locale/target/player_fr.xml b/client/src/locale/target/player_fr.xml
deleted file mode 100644 (file)
index eafa4ba..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--XLIFF document generated by Zanata. Visit http://zanata.org for more infomation.-->
-<xliff xmlns="urn:oasis:names:tc:xliff:document:1.1" xmlns:xyz="urn:appInfo:Items" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.1 http://www.oasis-open.org/committees/xliff/documents/xliff-core-1.1.xsd" version="1.1">
-  <file source-language="en-US" datatype="plaintext" original="" target-language="fr">
-    <body>
-      <trans-unit id="Audio Player">
-        <source>Audio Player</source>
-        <target>Lecteur audio</target>
-      </trans-unit>
-      <trans-unit id="Video Player">
-        <source>Video Player</source>
-        <target>Lecteur vidéo</target>
-      </trans-unit>
-      <trans-unit id="Play">
-        <source>Play</source>
-        <target>Lecture</target>
-      </trans-unit>
-      <trans-unit id="Pause">
-        <source>Pause</source>
-        <target>Pause</target>
-      </trans-unit>
-      <trans-unit id="Replay">
-        <source>Replay</source>
-        <target>Revoir</target>
-      </trans-unit>
-      <trans-unit id="Current Time">
-        <source>Current Time</source>
-        <target>Temps actuel</target>
-      </trans-unit>
-      <trans-unit id="Duration">
-        <source>Duration</source>
-        <target>Durée</target>
-      </trans-unit>
-      <trans-unit id="Remaining Time">
-        <source>Remaining Time</source>
-        <target>Temps restant</target>
-      </trans-unit>
-      <trans-unit id="Stream Type">
-        <source>Stream Type</source>
-        <target>Type de flux</target>
-      </trans-unit>
-      <trans-unit id="LIVE">
-        <source>LIVE</source>
-        <target>EN DIRECT</target>
-      </trans-unit>
-      <trans-unit id="Loaded">
-        <source>Loaded</source>
-        <target>Chargé</target>
-      </trans-unit>
-      <trans-unit id="Progress">
-        <source>Progress</source>
-        <target>Progression</target>
-      </trans-unit>
-      <trans-unit id="Progress Bar">
-        <source>Progress Bar</source>
-        <target>Barre de progression</target>
-      </trans-unit>
-      <trans-unit id="progress bar timing: currentTime={1} duration={2}">
-        <source>{1} of {2}</source>
-        <target>{1} de {2}</target>
-      </trans-unit>
-      <trans-unit id="Fullscreen">
-        <source>Fullscreen</source>
-        <target>Plein écran</target>
-      </trans-unit>
-      <trans-unit id="Non-Fullscreen">
-        <source>Non-Fullscreen</source>
-        <target>Fenêtré</target>
-      </trans-unit>
-      <trans-unit id="Mute">
-        <source>Mute</source>
-        <target>Sourdine</target>
-      </trans-unit>
-      <trans-unit id="Unmute">
-        <source>Unmute</source>
-        <target>Son activé</target>
-      </trans-unit>
-      <trans-unit id="Playback Rate">
-        <source>Playback Rate</source>
-        <target>Vitesse de lecture</target>
-      </trans-unit>
-      <trans-unit id="Subtitles">
-        <source>Subtitles</source>
-        <target>Sous-titres</target>
-      </trans-unit>
-      <trans-unit id="subtitles off">
-        <source>subtitles off</source>
-        <target>Sous-titres désactivés</target>
-      </trans-unit>
-      <trans-unit id="Captions">
-        <source>Captions</source>
-        <target>Sous-titres transcrits</target>
-      </trans-unit>
-      <trans-unit id="captions off">
-        <source>captions off</source>
-        <target>Sous-titres transcrits désactivés</target>
-      </trans-unit>
-      <trans-unit id="Chapters">
-        <source>Chapters</source>
-        <target>Chapitres</target>
-      </trans-unit>
-      <trans-unit id="Descriptions">
-        <source>Descriptions</source>
-        <target>Descriptions</target>
-      </trans-unit>
-      <trans-unit id="descriptions off">
-        <source>descriptions off</source>
-        <target>descriptions désactivées</target>
-      </trans-unit>
-      <trans-unit id="Audio Track">
-        <source>Audio Track</source>
-        <target>Piste audio</target>
-      </trans-unit>
-      <trans-unit id="Volume Level">
-        <source>Volume Level</source>
-        <target>Niveau de volume</target>
-      </trans-unit>
-      <trans-unit id="You aborted the media playback">
-        <source>You aborted the media playback</source>
-        <target>Vous avez interrompu la lecture de la vidéo.</target>
-      </trans-unit>
-      <trans-unit id="A network error caused the media download to fail part-way.">
-        <source>A network error caused the media download to fail part-way.</source>
-        <target>Une erreur de réseau a interrompu le téléchargement de la vidéo.</target>
-      </trans-unit>
-      <trans-unit id="The media could not be loaded, either because the server or network failed or because the format is not supported.">
-        <source>The media could not be loaded, either because the server or network failed or because the format is not supported.</source>
-        <target>Cette vidéo n'a pas pu être chargée, soit parce que le serveur ou le réseau a échoué ou parce que le format n'est pas reconnu.</target>
-      </trans-unit>
-      <trans-unit id="The media playback was aborted due to a corruption problem or because the media used features your browser did not support.">
-        <source>The media playback was aborted due to a corruption problem or because the media used features your browser did not support.</source>
-        <target>La lecture de la vidéo a été interrompue à cause d'un problème de corruption ou parce que la vidéo utilise des fonctionnalités non prises en charge par votre navigateur.</target>
-      </trans-unit>
-      <trans-unit id="No compatible source was found for this media.">
-        <source>No compatible source was found for this media.</source>
-        <target>Aucune source compatible n'a été trouvée pour cette vidéo.</target>
-      </trans-unit>
-      <trans-unit id="The media is encrypted and we do not have the keys to decrypt it.">
-        <source>The media is encrypted and we do not have the keys to decrypt it.</source>
-        <target>Le média est chiffré et nous n'avons pas les clés pour le déchiffrer.</target>
-      </trans-unit>
-      <trans-unit id="Play Video">
-        <source>Play Video</source>
-        <target>Lire la vidéo</target>
-      </trans-unit>
-      <trans-unit id="Close">
-        <source>Close</source>
-        <target>Fermer</target>
-      </trans-unit>
-      <trans-unit id="Close Modal Dialog">
-        <source>Close Modal Dialog</source>
-        <target>Fermer la boîte de dialogue modale</target>
-      </trans-unit>
-      <trans-unit id="Modal Window">
-        <source>Modal Window</source>
-        <target>Fenêtre modale</target>
-      </trans-unit>
-      <trans-unit id="This is a modal window">
-        <source>This is a modal window</source>
-        <target>Ceci est une fenêtre modale</target>
-      </trans-unit>
-      <trans-unit id="This modal can be closed by pressing the Escape key or activating the close button.">
-        <source>This modal can be closed by pressing the Escape key or activating the close button.</source>
-        <target>Ce modal peut être fermé en appuyant sur la touche Échap ou activer le bouton de fermeture.</target>
-      </trans-unit>
-      <trans-unit id=", opens captions settings dialog">
-        <source>, opens captions settings dialog</source>
-        <target>, ouvrir les paramètres des sous-titres transcrits</target>
-      </trans-unit>
-      <trans-unit id=", opens subtitles settings dialog">
-        <source>, opens subtitles settings dialog</source>
-        <target>, ouvrir les paramètres des sous-titres</target>
-      </trans-unit>
-      <trans-unit id=", opens descriptions settings dialog">
-        <source>, opens descriptions settings dialog</source>
-        <target>, ouvrir les paramètres des descriptions</target>
-      </trans-unit>
-      <trans-unit id=", selected">
-        <source>, selected</source>
-        <target>, sélectionné</target>
-      </trans-unit>
-      <trans-unit id="captions settings">
-        <source>captions settings</source>
-        <target>Paramètres des sous-titres transcrits</target>
-      </trans-unit>
-      <trans-unit id="subtitles settings">
-        <source>subititles settings</source>
-        <target>Paramètres des sous-titres</target>
-      </trans-unit>
-      <trans-unit id="descriptions settings">
-        <source>descriptions settings</source>
-        <target>Paramètres des descriptions</target>
-      </trans-unit>
-      <trans-unit id="Text">
-        <source>Text</source>
-        <target>Texte</target>
-      </trans-unit>
-      <trans-unit id="White">
-        <source>White</source>
-        <target>Blanc</target>
-      </trans-unit>
-      <trans-unit id="Black">
-        <source>Black</source>
-        <target>Noir</target>
-      </trans-unit>
-      <trans-unit id="Red">
-        <source>Red</source>
-        <target>Rouge</target>
-      </trans-unit>
-      <trans-unit id="Green">
-        <source>Green</source>
-        <target>Vert</target>
-      </trans-unit>
-      <trans-unit id="Blue">
-        <source>Blue</source>
-        <target>Bleu</target>
-      </trans-unit>
-      <trans-unit id="Yellow">
-        <source>Yellow</source>
-        <target>Jaune</target>
-      </trans-unit>
-      <trans-unit id="Magenta">
-        <source>Magenta</source>
-        <target>Magenta</target>
-      </trans-unit>
-      <trans-unit id="Cyan">
-        <source>Cyan</source>
-        <target>Cyan</target>
-      </trans-unit>
-      <trans-unit id="Background">
-        <source>Background</source>
-        <target>Arrière-plan</target>
-      </trans-unit>
-      <trans-unit id="Window">
-        <source>Window</source>
-        <target>Fenêtre</target>
-      </trans-unit>
-      <trans-unit id="Transparent">
-        <source>Transparent</source>
-        <target>Transparent</target>
-      </trans-unit>
-      <trans-unit id="Semi-Transparent">
-        <source>Semi-Transparent</source>
-        <target>Semi-transparent</target>
-      </trans-unit>
-      <trans-unit id="Opaque">
-        <source>Opaque</source>
-        <target>Opaque</target>
-      </trans-unit>
-      <trans-unit id="Font Size">
-        <source>Font Size</source>
-        <target>Taille des caractères</target>
-      </trans-unit>
-      <trans-unit id="Text Edge Style">
-        <source>Text Edge Style</source>
-        <target>Style des contours du texte</target>
-      </trans-unit>
-      <trans-unit id="None">
-        <source>None</source>
-        <target>Aucun</target>
-      </trans-unit>
-      <trans-unit id="Raised">
-        <source>Raised</source>
-        <target>Élevé</target>
-      </trans-unit>
-      <trans-unit id="Depressed">
-        <source>Depressed</source>
-        <target>Enfoncé</target>
-      </trans-unit>
-      <trans-unit id="Uniform">
-        <source>Uniform</source>
-        <target>Uniforme</target>
-      </trans-unit>
-      <trans-unit id="Dropshadow">
-        <source>Dropshadow</source>
-        <target>Ombre portée</target>
-      </trans-unit>
-      <trans-unit id="Font Family">
-        <source>Font Family</source>
-        <target>Familles de polices</target>
-      </trans-unit>
-      <trans-unit id="Proportional Sans-Serif">
-        <source>Proportional Sans-Serif</source>
-        <target>Polices à chasse variable sans empattement (Proportional Sans-Serif)</target>
-      </trans-unit>
-      <trans-unit id="Monospace Sans-Serif">
-        <source>Monospace Sans-Serif</source>
-        <target>Polices à chasse fixe sans empattement (Monospace Sans-Serif)</target>
-      </trans-unit>
-      <trans-unit id="Proportional Serif">
-        <source>Proportional Serif</source>
-        <target>Polices à chasse variable avec empattement (Proportional Serif)</target>
-      </trans-unit>
-      <trans-unit id="Monospace Serif">
-        <source>Monospace Serif</source>
-        <target>Polices à chasse fixe avec empattement (Monospace Serif)</target>
-      </trans-unit>
-      <trans-unit id="Casual">
-        <source>Casual</source>
-        <target>Manuscrite</target>
-      </trans-unit>
-      <trans-unit id="Script">
-        <source>Script</source>
-        <target>Scripte</target>
-      </trans-unit>
-      <trans-unit id="Small Caps">
-        <source>Small Caps</source>
-        <target>Petites capitales</target>
-      </trans-unit>
-      <trans-unit id="Reset">
-        <source>Reset</source>
-        <target>Réinitialiser</target>
-      </trans-unit>
-      <trans-unit id="restore all settings to the default values">
-        <source>restore all settings to the default values</source>
-        <target>Restaurer tous les paramètres aux valeurs par défaut</target>
-      </trans-unit>
-      <trans-unit id="Done">
-        <source>Done</source>
-        <target>Terminé</target>
-      </trans-unit>
-      <trans-unit id="Caption Settings Dialog">
-        <source>Caption Settings Dialog</source>
-        <target>Boîte de dialogue des paramètres des sous-titres transcrits</target>
-      </trans-unit>
-      <trans-unit id="Beginning of dialog window. Escape will cancel and close the window.">
-        <source>Beginning of dialog window. Escape will cancel and close the window.</source>
-        <target>Début de la fenêtre de dialogue. La touche d'échappement annulera et fermera la fenêtre.</target>
-      </trans-unit>
-      <trans-unit id="End of dialog window.">
-        <source>End of dialog window.</source>
-        <target>Fin de la fenêtre de dialogue.</target>
-      </trans-unit>
-      <trans-unit id="{1} is loading.">
-        <source>{1} is loading.</source>
-        <target>{1} est en train de charger</target>
-      </trans-unit>
-      <trans-unit id="Quality">
-        <source>Quality</source>
-        <target>Qualité</target>
-      </trans-unit>
-      <trans-unit id="Auto">
-        <source>Auto</source>
-        <target>Auto</target>
-      </trans-unit>
-      <trans-unit id="Speed">
-        <source>Speed</source>
-        <target>Vitesse</target>
-      </trans-unit>
-      <trans-unit id="peers">
-        <source>peers</source>
-        <target>pairs</target>
-      </trans-unit>
-      <trans-unit id="Go to the video page">
-        <source>Go to the video page</source>
-        <target>Aller sur la page de la vidéo</target>
-      </trans-unit>
-      <trans-unit id="Settings">
-        <source>Settings</source>
-        <target>Paramètres</target>
-      </trans-unit>
-      <trans-unit id="Uses P2P, others may know you are watching this video.">
-        <source>Uses P2P, others may know you are watching this video.</source>
-        <target>Utilise le P2P, d'autres personnes pourraient savoir que vous regardez cette vidéo.</target>
-      </trans-unit>
-      <trans-unit id="Copy the video URL">
-        <source>Copy the video URL</source>
-        <target>Copier le lien de la vidéo</target>
-      </trans-unit>
-      <trans-unit id="Copy the video URL at the current time">
-        <source>Copy the video URL at the current time</source>
-        <target>Copier le lien de la vidéo à partir de cette séquence</target>
-      </trans-unit>
-      <trans-unit id="Copy embed code">
-        <source>Copy embed code</source>
-        <target>Copier le code d'intégration</target>
-      </trans-unit>
-    </body>
-  </file></xliff>
\ No newline at end of file
diff --git a/client/src/locale/target/server_fr.json b/client/src/locale/target/server_fr.json
new file mode 100644 (file)
index 0000000..43216ad
--- /dev/null
@@ -0,0 +1 @@
+{"Music":"Musique","Films":"Films","Vehicles":"Transport","Art":"Art","Sports":"Sports","Travels":"Voyages","Gaming":"Jeux vidéos","People":"People","Comedy":"Humour","Entertainment":"Divertissement","News":"Actualités","How To":"Tutoriel","Education":"Éducation","Activism":"Activisme","Science & Technology":"Science & Technologie","Animals":"Animaux","Kids":"Enfants","Food":"Cuisine","Attribution":"Attribution","Attribution - Share Alike":"Attribution - Partage dans les mêmes conditions","Attribution - No Derivatives":"Attribution - Pas d'oeuvre dérivée","Attribution - Non Commercial":"Attribution - Utilisation non commerciale","Attribution - Non Commercial - Share Alike":"Attribution - Utilisation non commerciale - Partage dans les mêmes conditions","Attribution - Non Commercial - No Derivatives":"Attribution - Utilisation non commerciale - Pas d'oeuvre dérivée","Public Domain Dedication":"Domaine public","Public":"Publique","Unlisted":"Non listée","Private":"Privée","French":"Français","French Sign Language":"Langage des signes français","Misc":"Divers","Unknown":"Inconnu"}
\ No newline at end of file
index d8a87f2915c659c4bb9c4c2cb49e68917f031f4c..3519afd47dcec9d15c420fc3d156cfba6f05868b 100755 (executable)
@@ -1,12 +1,15 @@
 import * as jsToXliff12 from 'xliff/jsToXliff12'
 import { writeFile } from 'fs'
 import { join } from 'path'
+import { buildLanguages, VIDEO_CATEGORIES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../server/initializers/constants'
+import { values } from 'lodash'
 
-// First, the player
-const playerSource = join(__dirname, '../../../client/src/locale/source/videojs_en_US.json')
-const playerTarget = join(__dirname, '../../../client/src/locale/source/player_en_US.xml')
+type TranslationType = {
+  target: string
+  data: { [id: string]: string }
+}
 
-const videojs = require(playerSource)
+const videojs = require(join(__dirname, '../../../client/src/locale/source/videojs_en_US.json'))
 const playerKeys = {
   'Quality': 'Quality',
   'Auto': 'Auto',
@@ -19,36 +22,65 @@ const playerKeys = {
   'Copy the video URL at the current time': 'Copy the video URL at the current time',
   'Copy embed code': 'Copy embed code'
 }
-
-const obj = {
-  resources: {
-    namespace1: {}
-  }
+const playerTranslations = {
+  target: join(__dirname, '../../../client/src/locale/source/player_en_US.xml'),
+  data: Object.assign({}, videojs, playerKeys)
 }
 
-for (const sourceObject of [ videojs, playerKeys ]) {
-  Object.keys(sourceObject).forEach(k => obj.resources.namespace1[ k ] = { source: sourceObject[ k ] })
+// Server keys
+const serverKeys: any = {}
+values(VIDEO_CATEGORIES)
+  .concat(values(VIDEO_LICENCES))
+  .concat(values(VIDEO_PRIVACIES))
+  .forEach(v => serverKeys[v] = v)
+
+// ISO 639 keys
+const languages = buildLanguages()
+Object.keys(languages).forEach(k => serverKeys[languages[k]] = languages[k])
+
+// More keys
+Object.assign(serverKeys, {
+  'Misc': 'Misc',
+  'Unknown': 'Unknown'
+})
+
+const serverTranslations = {
+  target: join(__dirname, '../../../client/src/locale/source/server_en_US.xml'),
+  data: serverKeys
 }
 
-saveToXliffFile(playerTarget, obj, err => {
-  if (err) {
-    console.error(err)
-    process.exit(-1)
-  }
+saveToXliffFile(playerTranslations, err => {
+  if (err) return handleError(err)
+
+  saveToXliffFile(serverTranslations, err => {
+    if (err) return handleError(err)
 
-  process.exit(0)
+    process.exit(0)
+  })
 })
 
 // Then, the server strings
 
-function saveToXliffFile (targetPath: string, obj: any, cb: Function) {
+function saveToXliffFile (jsonTranslations: TranslationType, cb: Function) {
+  const obj = {
+    resources: {
+      namespace1: {}
+    }
+  }
+  Object.keys(jsonTranslations.data).forEach(k => obj.resources.namespace1[ k ] = { source: jsonTranslations.data[ k ] })
+
   jsToXliff12(obj, (err, res) => {
     if (err) return cb(err)
 
-    writeFile(playerTarget, res, err => {
+    writeFile(jsonTranslations.target, res, err => {
       if (err) return cb(err)
 
       return cb(null)
     })
   })
 }
+
+function handleError (err: any) {
+  console.error(err)
+  process.exit(-1)
+}
\ No newline at end of file
index 34784ac111c95245dbbc988e574f126a5fb0892e..fa5a71d659133430aa7b5f4052fd701f4f5d94ef 100755 (executable)
@@ -1,33 +1,53 @@
 import * as xliff12ToJs from 'xliff/xliff12ToJs'
-import { readFileSync, writeFile } from 'fs'
+import { unlink, readFileSync, writeFile } from 'fs'
 import { join } from 'path'
+import { buildFileLocale, I18N_LOCALES, isDefaultLocale } from '../../shared/models/i18n/i18n'
+import { eachSeries } from 'async'
 
-// First, the player
-const playerSource = join(__dirname, '../../../client/src/locale/target/player_fr.xml')
-const playerTarget = join(__dirname, '../../../client/src/locale/target/player_fr.json')
+const sources: string[] = []
+const availableLocales = Object.keys(I18N_LOCALES)
+                               .filter(l => isDefaultLocale(l) === false)
+                               .map(l => buildFileLocale(l))
 
-// Remove the two first lines our xliff module does not like
-let playerFile = readFileSync(playerSource).toString()
-playerFile = removeFirstLine(playerFile)
-playerFile = removeFirstLine(playerFile)
-
-xliff12ToJs(playerFile, (err, res) => {
-  if (err) {
-    console.error(err)
-    process.exit(-1)
+for (const file of [ 'server', 'player' ]) {
+  for (const locale of availableLocales) {
+    sources.push(join(__dirname, '../../../client/src/locale/target/', `${file}_${locale}.xml`))
   }
+}
 
-  const json = createJSONString(res)
-  writeFile(playerTarget, json, err => {
-    if (err) {
-      console.error(err)
-      process.exit(-1)
-    }
+eachSeries(sources, (source, cb) => {
+  xliffFile2JSON(source, cb)
+}, err => {
+  if (err) return handleError(err)
 
-    process.exit(0)
-  })
+  process.exit(0)
 })
 
+function handleError (err: any) {
+  console.error(err)
+  process.exit(-1)
+}
+
+function xliffFile2JSON (filePath: string, cb) {
+  const fileTarget = filePath.replace('.xml', '.json')
+
+  // Remove the two first lines our xliff module does not like
+  let fileContent = readFileSync(filePath).toString()
+  fileContent = removeFirstLine(fileContent)
+  fileContent = removeFirstLine(fileContent)
+
+  xliff12ToJs(fileContent, (err, res) => {
+    if (err) return cb(err)
+
+    const json = createJSONString(res)
+    writeFile(fileTarget, json, err => {
+      if (err) return cb(err)
+
+      return unlink(filePath, cb)
+    })
+  })
+}
+
 function removeFirstLine (str: string) {
   return str.substring(str.indexOf('\n') + 1)
 }
index b153f6086fc0fbecdbb366383cc2e2882b4ba53d..ec78a4bbc0cbcf25e1376d3fd8038ffafff81f1d 100644 (file)
@@ -48,8 +48,11 @@ clientsRouter.use('/client', express.static(distPath, { maxAge: STATIC_MAX_AGE }
 clientsRouter.use('/client/assets/images', express.static(assetsImagesPath, { maxAge: STATIC_MAX_AGE }))
 
 clientsRouter.use('/client/locales/:locale/:file.json', function (req, res) {
-  if (req.params.locale === 'fr' && req.params.file === 'player') {
-    return res.sendFile(join(__dirname, '../../../client/dist/locale/player_fr.json'))
+  const locale = req.params.locale
+  const file = req.params.file
+
+  if (is18nLocale(locale) && [ 'player', 'server' ].indexOf(file) !== -1) {
+    return res.sendFile(join(__dirname, `../../../client/dist/locale/${file}_${locale}.json`))
   }
 
   return res.sendStatus(404)
index 26ee3db47526d471d12f32d153a2812b3d4712ec..9b459c2414770c5fcf622cc3925313dcf76fc41d 100644 (file)
@@ -500,7 +500,8 @@ export {
   STATIC_DOWNLOAD_PATHS,
   RATES_LIMIT,
   JOB_COMPLETED_LIFETIME,
-  VIDEO_VIEW_LIFETIME
+  VIDEO_VIEW_LIFETIME,
+  buildLanguages
 }
 
 // ---------------------------------------------------------------------------