]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add i18n attributes
authorChocobozzz <me@florianbigard.com>
Mon, 4 Jun 2018 14:21:17 +0000 (16:21 +0200)
committerChocobozzz <me@florianbigard.com>
Tue, 5 Jun 2018 06:43:01 +0000 (08:43 +0200)
96 files changed:
client/src/app/+accounts/account-about/account-about.component.html
client/src/app/+accounts/account-about/account-about.component.ts
client/src/app/+accounts/account-video-channels/account-video-channels.component.html
client/src/app/+accounts/account-videos/account-videos.component.ts
client/src/app/+accounts/accounts.component.html
client/src/app/+admin/admin.component.html
client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
client/src/app/+admin/follows/followers-list/followers-list.component.html
client/src/app/+admin/follows/followers-list/followers-list.component.ts
client/src/app/+admin/follows/following-add/following-add.component.html
client/src/app/+admin/follows/following-add/following-add.component.ts
client/src/app/+admin/follows/following-list/following-list.component.html
client/src/app/+admin/follows/following-list/following-list.component.ts
client/src/app/+admin/follows/follows.component.html
client/src/app/+admin/jobs/index.ts
client/src/app/+admin/jobs/jobs-list/jobs-list.component.html
client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts
client/src/app/+admin/users/shared/user.service.ts
client/src/app/+admin/users/user-edit/user-create.component.ts
client/src/app/+admin/users/user-edit/user-edit.component.html
client/src/app/+admin/users/user-edit/user-update.component.ts
client/src/app/+admin/users/user-list/user-list.component.html
client/src/app/+admin/users/user-list/user-list.component.ts
client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts
client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html
client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts
client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html
client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts
client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.html
client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts
client/src/app/+my-account/my-account-settings/my-account-settings.component.html
client/src/app/+my-account/my-account-settings/my-account-settings.component.ts
client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html
client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts
client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts
client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html
client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
client/src/app/+my-account/my-account-videos/my-account-videos.component.html
client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
client/src/app/+my-account/my-account.component.html
client/src/app/+page-not-found/page-not-found.component.html
client/src/app/+video-channels/video-channel-about/video-channel-about.component.html
client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
client/src/app/+video-channels/video-channels.component.html
client/src/app/about/about.component.html
client/src/app/about/about.component.ts
client/src/app/core/auth/auth.service.ts
client/src/app/core/confirm/confirm.component.html
client/src/app/core/confirm/confirm.component.ts
client/src/app/header/header.component.html
client/src/app/login/login.component.html
client/src/app/login/login.component.ts
client/src/app/menu/menu.component.html
client/src/app/menu/menu.component.ts
client/src/app/reset-password/reset-password.component.html
client/src/app/reset-password/reset-password.component.ts
client/src/app/shared/forms/markdown-textarea.component.html
client/src/app/shared/forms/markdown-textarea.component.ts
client/src/app/shared/guards/can-deactivate-guard.service.ts
client/src/app/shared/misc/edit-button.component.html
client/src/app/shared/misc/from-now.pipe.ts
client/src/app/shared/misc/help.component.html
client/src/app/shared/rest/rest-extractor.service.ts
client/src/app/shared/video/abstract-video-list.html
client/src/app/shared/video/abstract-video-list.ts
client/src/app/shared/video/video-miniature.component.html
client/src/app/shared/video/video-thumbnail.component.html
client/src/app/signup/signup.component.html
client/src/app/signup/signup.component.ts
client/src/app/videos/+video-edit/shared/video-edit.component.html
client/src/app/videos/+video-edit/shared/video-image.component.html
client/src/app/videos/+video-edit/video-add.component.html
client/src/app/videos/+video-edit/video-add.component.ts
client/src/app/videos/+video-edit/video-update.component.html
client/src/app/videos/+video-edit/video-update.component.ts
client/src/app/videos/+video-watch/comment/video-comment-add.component.html
client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
client/src/app/videos/+video-watch/comment/video-comment.component.html
client/src/app/videos/+video-watch/comment/video-comments.component.html
client/src/app/videos/+video-watch/comment/video-comments.component.ts
client/src/app/videos/+video-watch/modal/video-download.component.html
client/src/app/videos/+video-watch/modal/video-report.component.html
client/src/app/videos/+video-watch/modal/video-report.component.ts
client/src/app/videos/+video-watch/modal/video-share.component.html
client/src/app/videos/+video-watch/modal/video-share.component.ts
client/src/app/videos/+video-watch/modal/video-support.component.html
client/src/app/videos/video-list/video-local.component.ts
client/src/app/videos/video-list/video-recently-added.component.ts
client/src/app/videos/video-list/video-search.component.ts
client/src/app/videos/video-list/video-trending.component.ts
client/src/locale/source/messages_en_US.xml

index eae1cb509d708f9892073cc590d6ce62e1f9da08..b178f5cc867e798c4d2072da9f74f8a362d7b2d3 100644 (file)
@@ -1,12 +1,12 @@
 <div *ngIf="account" class="row">
   <div class="block col-md-6 col-sm-12">
-    <div class="small-title">Description</div>
+    <div i18n class="small-title">Description</div>
     <div class="content">{{ getAccountDescription() }}</div>
   </div>
 
   <div class="block col-md-6 col-sm-12">
-    <div class="small-title">Stats</div>
+    <div i18n class="small-title">Stats</div>
 
-    <div class="content">Joined {{ account.createdAt | date }}</div>
+    <div i18n class="content">Joined {{ account.createdAt | date }}</div>
   </div>
 </div>
\ No newline at end of file
index f063df392624651f608f2e9d2400836235ba9d0a..4086510ba51c523c05ff89f168a2f11b776ea413 100644 (file)
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'
 import { ActivatedRoute } from '@angular/router'
 import { Account } from '@app/shared/account/account.model'
 import { AccountService } from '@app/shared/account/account.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-about',
@@ -12,7 +13,8 @@ export class AccountAboutComponent implements OnInit {
   account: Account
 
   constructor (
-    protected route: ActivatedRoute,
+    private route: ActivatedRoute,
+    private i18n: I18n,
     private accountService: AccountService
   ) { }
 
@@ -25,6 +27,6 @@ export class AccountAboutComponent implements OnInit {
   getAccountDescription () {
     if (this.account.description) return this.account.description
 
-    return 'No description'
+    return this.i18n('No description')
   }
 }
index d20b40c6005a18220ea1fa76a2aeb92d1bac059f..bcd3beaf0a86259f18040ef6902b6d3531c2c297 100644 (file)
@@ -1,11 +1,11 @@
 <div *ngIf="account" class="row">
   <a
     *ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.uuid ]"
-    class="video-channel" title="See this video channel"
+    class="video-channel" i18n-title title="See this video channel"
   >
     <img [src]="videoChannel.avatarUrl" alt="Avatar" />
 
     <div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
-    <div class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
+    <div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
   </a>
 </div>
\ No newline at end of file
index eca9fb6b74ae75797571bef7a7f9dff60f9de9c7..7b7629480226c63975500516e12ff9b3e6541863 100644 (file)
@@ -10,6 +10,7 @@ import { VideoService } from '../../shared/video/video.service'
 import { Account } from '@app/shared/account/account.model'
 import { AccountService } from '@app/shared/account/account.service'
 import { tap } from 'rxjs/operators'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-videos',
@@ -20,7 +21,7 @@ import { tap } from 'rxjs/operators'
   ]
 })
 export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
-  titlePage = 'Published videos'
+  titlePage: string
   marginContent = false // Disable margin
   currentRoute = '/account/videos'
   loadOnInit = false
@@ -34,10 +35,13 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
     protected notificationsService: NotificationsService,
     protected confirmService: ConfirmService,
     protected location: Location,
+    protected i18n: I18n,
     private accountService: AccountService,
     private videoService: VideoService
   ) {
     super()
+
+    this.titlePage = this.i18n('Published videos')
   }
 
   ngOnInit () {
@@ -63,7 +67,11 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
 
     return this.videoService
                .getAccountVideos(this.account, newPagination, this.sort)
-               .pipe(tap(({ totalVideos }) => this.titlePage = `Published ${totalVideos} videos`))
+               .pipe(
+                 tap(({ totalVideos }) => {
+                   this.titlePage = this.i18n('Published {{ totalVideos }} videos', { totalVideos })
+                 })
+               )
   }
 
   generateSyndicationList () {
index e872bda03ed68be0fbeedd48d3126b816776264f..69f6482697c26fa4e06f4f1184b0ead9481ae2b8 100644 (file)
@@ -9,16 +9,16 @@
           <div class="actor-display-name">{{ account.displayName }}</div>
           <div class="actor-name">{{ account.nameWithHost }}</div>
         </div>
-        <div class="actor-followers">{{ account.followersCount }} subscribers</div>
+        <div i18n class="actor-followers">{{ account.followersCount }} subscribers</div>
       </div>
     </div>
 
     <div class="links">
-      <a routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
+      <a i18n routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
 
-      <a routerLink="video-channels" routerLinkActive="active" class="title-page">Video channels</a>
+      <a i18n routerLink="video-channels" routerLinkActive="active" class="title-page">Video channels</a>
 
-      <a routerLink="about" routerLinkActive="active" class="title-page">About</a>
+      <a i18n routerLink="about" routerLinkActive="active" class="title-page">About</a>
     </div>
   </div>
 
index e4644498b5052c6297d9f915bf460044d1f695b0..1b2b89c3ad12b25bd7febe6f4b4c6a6d0c37b1fe 100644 (file)
@@ -1,26 +1,26 @@
 <div class="row">
   <div class="sub-menu">
-    <a *ngIf="hasUsersRight()" routerLink="/admin/users" routerLinkActive="active" class="title-page">
+    <a i18n *ngIf="hasUsersRight()" routerLink="/admin/users" routerLinkActive="active" class="title-page">
       Users
     </a>
 
-    <a *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active" class="title-page">
+    <a i18n *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active" class="title-page">
       Manage follows
     </a>
 
-    <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active" class="title-page">
+    <a i18n *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active" class="title-page">
       Video abuses
     </a>
 
-    <a *ngIf="hasVideoBlacklistRight()" routerLink="/admin/video-blacklist" routerLinkActive="active" class="title-page">
+    <a i18n *ngIf="hasVideoBlacklistRight()" routerLink="/admin/video-blacklist" routerLinkActive="active" class="title-page">
       Video blacklist
     </a>
 
-    <a *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active" class="title-page">
+    <a i18n *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active" class="title-page">
       Jobs
     </a>
 
-    <a *ngIf="hasConfigRight()" routerLink="/admin/config" routerLinkActive="active" class="title-page">
+    <a i18n *ngIf="hasConfigRight()" routerLink="/admin/config" routerLinkActive="active" class="title-page">
       Configuration
     </a>
   </div>
index 8a1e33c566116d1246247240d723a8a69daf3a46..4263b7b5facfc9246ea84be0222863c715dc6207 100644 (file)
@@ -4,13 +4,13 @@
 
     <tab heading="Basic configuration">
 
-      <div class="inner-form-title">Instance</div>
+      <div i18n class="inner-form-title">Instance</div>
 
       <div class="form-group">
-        <label for="instanceName">Name</label>
+        <label i18n for="instanceName">Name</label>
         <input
-            type="text" id="instanceName"
-            formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
+          type="text" id="instanceName"
+          formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
         >
         <div *ngIf="formErrors.instanceName" class="form-error">
           {{ formErrors.instanceName }}
       </div>
 
       <div class="form-group">
-        <label for="instanceShortDescription">Short description</label>
+        <label i18n for="instanceShortDescription">Short description</label>
         <textarea
-            id="instanceShortDescription" formControlName="instanceShortDescription"
-            [ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
+          id="instanceShortDescription" formControlName="instanceShortDescription"
+          [ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
         ></textarea>
         <div *ngIf="formErrors.instanceShortDescription" class="form-error">
           {{ formErrors.instanceShortDescription }}
       </div>
 
       <div class="form-group">
-        <label for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
+        <label i18n for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
         <my-markdown-textarea
-            id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
-            [classes]="{ 'input-error': formErrors['instanceDescription'] }"
+          id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
+          [classes]="{ 'input-error': formErrors['instanceDescription'] }"
         ></my-markdown-textarea>
         <div *ngIf="formErrors.instanceDescription" class="form-error">
           {{ formErrors.instanceDescription }}
       </div>
 
       <div class="form-group">
-        <label for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
+        <label i18n for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
         <my-markdown-textarea
-            id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
-            [ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
+          id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
+          [ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
         ></my-markdown-textarea>
         <div *ngIf="formErrors.instanceTerms" class="form-error">
           {{ formErrors.instanceTerms }}
       </div>
 
       <div class="form-group">
-        <label for="instanceDefaultClientRoute">Default client route</label>
+        <label i18n for="instanceDefaultClientRoute">Default client route</label>
         <div class="peertube-select-container">
           <select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
-            <option value="/videos/trending">Videos Trending</option>
-            <option value="/videos/recently-added">Videos Recently Added</option>
-            <option value="/videos/local">Local videos</option>
+            <option i18n value="/videos/trending">Videos Trending</option>
+            <option i18n value="/videos/recently-added">Videos Recently Added</option>
+            <option i18n value="/videos/local">Local videos</option>
           </select>
         </div>
         <div *ngIf="formErrors.instanceDefaultClientRoute" class="form-error">
       </div>
 
       <div class="form-group">
-        <label for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
-        <my-help helpType="custom" customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."></my-help>
+        <label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
+        <my-help
+          helpType="custom" i18n-customHtml
+          customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."
+        ></my-help>
 
         <div class="peertube-select-container">
           <select id="instanceDefaultNSFWPolicy" formControlName="instanceDefaultNSFWPolicy">
-            <option value="do_not_list">Do not list</option>
-            <option value="blur">Blur thumbnails</option>
-            <option value="display">Display</option>
+            <option i18n value="do_not_list">Do not list</option>
+            <option i18n value="blur">Blur thumbnails</option>
+            <option i18n value="display">Display</option>
           </select>
         </div>
         <div *ngIf="formErrors.instanceDefaultNSFWPolicy" class="form-error">
         </div>
       </div>
 
-      <div class="inner-form-title">Signup</div>
+      <div i18n class="inner-form-title">Signup</div>
 
       <div class="form-group">
         <input type="checkbox" id="signupEnabled" formControlName="signupEnabled">
 
         <label for="signupEnabled"></label>
-        <label for="signupEnabled">Signup enabled</label>
+        <label i18n for="signupEnabled">Signup enabled</label>
       </div>
 
       <div *ngIf="isSignupEnabled()" class="form-group">
-        <label for="signupLimit">Signup limit</label>
+        <label i18n for="signupLimit">Signup limit</label>
         <input
-            type="text" id="signupLimit"
-            formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
+          type="text" id="signupLimit"
+          formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
         >
         <div *ngIf="formErrors.signupLimit" class="form-error">
           {{ formErrors.signupLimit }}
         </div>
       </div>
 
-      <div class="inner-form-title">Administrator</div>
+      <div i18n class="inner-form-title">Administrator</div>
 
       <div class="form-group">
-        <label for="adminEmail">Admin email</label>
+        <label i18n for="adminEmail">Admin email</label>
         <input
-            type="text" id="adminEmail"
-            formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
+          type="text" id="adminEmail"
+          formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
         >
         <div *ngIf="formErrors.adminEmail" class="form-error">
           {{ formErrors.adminEmail }}
         </div>
       </div>
 
-      <div class="inner-form-title">Users</div>
+      <div i18n class="inner-form-title">Users</div>
 
       <div class="form-group">
-        <label for="userVideoQuota">User default video quota</label>
+        <label i18n for="userVideoQuota">User default video quota</label>
         <div class="peertube-select-container">
           <select id="userVideoQuota" formControlName="userVideoQuota">
             <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
 
     <tab heading="Services">
 
-      <div class="inner-form-title">Twitter</div>
+      <div i18n class="inner-form-title">Twitter</div>
 
       <div class="form-group">
-        <label for="signupLimit">Your Twitter username</label>
-        <my-help helpType="custom" customHtml="Indicates the Twitter account for the website or platform on which the content was published."></my-help>
+        <label i18n for="signupLimit">Your Twitter username</label>
+        <my-help
+          helpType="custom" i18n-customHtml
+          customHtml="Indicates the Twitter account for the website or platform on which the content was published."
+        ></my-help>
         <input
-            type="text" id="servicesTwitterUsername"
-            formControlName="servicesTwitterUsername" [ngClass]="{ 'input-error': formErrors['servicesTwitterUsername'] }"
+          type="text" id="servicesTwitterUsername"
+          formControlName="servicesTwitterUsername" [ngClass]="{ 'input-error': formErrors['servicesTwitterUsername'] }"
         >
         <div *ngIf="formErrors.servicesTwitterUsername" class="form-error">
           {{ formErrors.servicesTwitterUsername }}
         <input type="checkbox" id="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted">
 
         <label for="servicesTwitterWhitelisted"></label>
-        <label for="servicesTwitterWhitelisted">Instance whitelisted by Twitter</label>
-        <my-help helpType="custom" customHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
+        <label i18n for="servicesTwitterWhitelisted">Instance whitelisted by Twitter</label>
+        <my-help
+          helpType="custom" i18n-customHtml
+          customHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
 If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
-Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."></my-help>
+Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."
+        ></my-help>
 
       </div>
     </tab>
 
     <tab heading="Advanced configuration">
 
-      <div class="inner-form-title">Transcoding</div>
+      <div i18n class="inner-form-title">Transcoding</div>
 
       <div class="form-group">
         <input type="checkbox" id="transcodingEnabled" formControlName="transcodingEnabled">
 
         <label for="transcodingEnabled"></label>
-        <label for="transcodingEnabled">Transcoding enabled</label>
+        <label i18n for="transcodingEnabled">Transcoding enabled</label>
       </div>
 
       <ng-template [ngIf]="isTranscodingEnabled()">
 
         <div class="form-group">
-          <label for="transcodingThreads">Transcoding threads</label>
+          <label i18n for="transcodingThreads">Transcoding threads</label>
           <div class="peertube-select-container">
             <select id="transcodingThreads" formControlName="transcodingThreads">
               <option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
@@ -191,33 +200,39 @@ Check this checkbox, save the configuration and test with a video URL of your in
               [formControlName]="getResolutionKey(resolution)"
           >
           <label [for]="getResolutionKey(resolution)"></label>
-          <label [for]="getResolutionKey(resolution)">Resolution {{ resolution }} enabled</label>
+          <label i18n [for]="getResolutionKey(resolution)">Resolution {{ resolution }} enabled</label>
         </div>
       </ng-template>
 
-      <div class="inner-form-title">Cache</div>
+      <div i18n class="inner-form-title">Cache</div>
 
       <div class="form-group">
-        <label for="cachePreviewsSize">Preview cache size</label>
-        <my-help helpType="custom" customHtml="Previews are not federated. We fetch them directly from the origin instance and cache them."></my-help>
+        <label i18n for="cachePreviewsSize">Preview cache size</label>
+        <my-help
+          helpType="custom" i18n-customHtml
+          customHtml="Previews are not federated. We fetch them directly from the origin instance and cache them."
+        ></my-help>
 
         <input
-            type="text" id="cachePreviewsSize"
-            formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
+          type="text" id="cachePreviewsSize"
+          formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
         >
         <div *ngIf="formErrors.cachePreviewsSize" class="form-error">
           {{ formErrors.cachePreviewsSize }}
         </div>
       </div>
 
-      <div class="inner-form-title">Customizations</div>
+      <div i18n class="inner-form-title">Customizations</div>
 
       <div class="form-group">
-        <label for="customizationJavascript">JavaScript</label>
-        <my-help helpType="custom" customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"></my-help>
+        <label i18n for="customizationJavascript">JavaScript</label>
+        <my-help
+          helpType="custom" i18n-customHtml
+          customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"
+        ></my-help>
         <textarea
-            id="customizationJavascript" formControlName="customizationJavascript"
-            [ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
+          id="customizationJavascript" formControlName="customizationJavascript"
+          [ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
         ></textarea>
         <div *ngIf="formErrors.customizationJavascript" class="form-error">
           {{ formErrors.customizationJavascript }}
@@ -228,25 +243,26 @@ Check this checkbox, save the configuration and test with a video URL of your in
         <label for="customizationCSS">CSS</label>
         <my-help
             helpType="custom"
+            i18n-customHtml
             customHtml="
               Write directly CSS code. Example:<br />
               <pre>
-    body {
+    body {{ '{' }}
       background-color: red;
-    }
+    {{ '}' }}
               </pre>
 
               Prepend with <em>#custom-css</em> to override styles. Example:
               <pre>
-    #custom-css .logged-in-email {
+    #custom-css .logged-in-email {{ '{' }}
       color: red;
-    }
+    {{ '}' }}
               </pre>
             "
         ></my-help>
         <textarea
-            id="customizationCSS" formControlName="customizationCSS"
-            [ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
+          id="customizationCSS" formControlName="customizationCSS"
+          [ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
         ></textarea>
         <div *ngIf="formErrors.customizationCSS" class="form-error">
           {{ formErrors.customizationCSS }}
@@ -255,5 +271,5 @@ Check this checkbox, save the configuration and test with a video URL of your in
     </tab>
   </tabset>
 
-  <input (click)="formValidated()" type="submit" value="Update configuration" [disabled]="!form.valid">
+  <input (click)="formValidated()" type="submit" i18n-value value="Update configuration" [disabled]="!form.valid">
 </form>
index a1e334a746af0533079781ebd09a81cb6af7a0c6..3f92054603c5fdcfcac6a43c88d5e1272118eeb1 100644 (file)
@@ -8,12 +8,15 @@ import { FormReactive, USER_VIDEO_QUOTA } from '@app/shared'
 import {
   ADMIN_EMAIL,
   CACHE_PREVIEWS_SIZE,
-  INSTANCE_NAME, INSTANCE_SHORT_DESCRIPTION, SERVICES_TWITTER_USERNAME,
+  INSTANCE_NAME,
+  INSTANCE_SHORT_DESCRIPTION,
+  SERVICES_TWITTER_USERNAME,
   SIGNUP_LIMIT,
   TRANSCODING_THREADS
 } from '@app/shared/forms/form-validators/custom-config'
 import { NotificationsService } from 'angular2-notifications'
 import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-edit-custom-config',
@@ -77,7 +80,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
     private notificationsService: NotificationsService,
     private configService: ConfigService,
     private serverService: ServerService,
-    private confirmService: ConfirmService
+    private confirmService: ConfirmService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -133,7 +137,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
           this.forceCheck()
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
@@ -156,11 +160,15 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
     if (customizations.length !== 0) {
       const customizationsText = customizations.join('/')
 
-      const message = `You set custom ${customizationsText}. ` +
-        'This could lead to security issues or bugs if you do not understand it. ' +
-        'Are you sure you want to update the configuration?'
-      const label = `Please type "I understand the ${customizationsText} I set" to confirm.`
-      const expectedInputValue = `I understand the ${customizationsText} I set`
+      // FIXME: i18n service does not support string concatenation
+      const message = this.i18n('You set custom {{ customizationsText }}. ', { customizationsText }) +
+        this.i18n('This could lead to security issues or bugs if you do not understand it. ') +
+        this.i18n('Are you sure you want to update the configuration?')
+      const label = this.i18n(
+        'Please type "I understand the {{ customizationsText }} I set" to confirm.',
+        { customizationsText }
+      )
+      const expectedInputValue = this.i18n('I understand the {{ customizationsText }} I set', { customizationsText})
 
       const confirmRes = await this.confirmService.confirmWithInput(message, label, expectedInputValue)
       if (confirmRes === false) return
@@ -223,10 +231,10 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
 
           this.updateForm()
 
-          this.notificationsService.success('Success', 'Configuration updated.')
+          this.notificationsService.success(this.i18n('Success'), this.i18n('Configuration updated.'))
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
index 85d2a2cf647838fd20949dbbb2a072e0c6f91634..1a6ed616a6cd21c0bbfb97e9866e0396219bef1f 100644 (file)
@@ -4,12 +4,12 @@
 >
   <ng-template pTemplate="header">
     <tr>
-      <th style="width: 60px">ID</th>
-      <th>Score</th>
-      <th>Name</th>
-      <th>Host</th>
-      <th>State</th>
-      <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
+      <th i18n style="width: 60px">ID</th>
+      <th i18n>Score</th>
+      <th i18n>Name</th>
+      <th i18n>Host</th>
+      <th i18n>State</th>
+      <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
     </tr>
   </ng-template>
 
index 69b3e5e58985121fdd23b4b529153a9391abd4f2..96fb67588ddda45617e239bfd19c7839ab0ac54e 100644 (file)
@@ -5,6 +5,7 @@ import { SortMeta } from 'primeng/primeng'
 import { AccountFollow } from '../../../../../../shared/models/actors/follow.model'
 import { RestPagination, RestTable } from '../../../shared'
 import { FollowService } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-followers-list',
@@ -20,7 +21,8 @@ export class FollowersListComponent extends RestTable implements OnInit {
 
   constructor (
     private notificationsService: NotificationsService,
-    private followService: FollowService
+    private followService: FollowService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -37,7 +39,7 @@ export class FollowersListComponent extends RestTable implements OnInit {
                           this.totalRecords = resultList.total
                         },
 
-                        err => this.notificationsService.error('Error', err.message)
+                        err => this.notificationsService.error(this.i18n('Error'), err.message)
                       )
   }
 }
index 25bab9d0dfea6e017d1474ed691277da995e1e36..72635048c55e1d82d707f3613aed779b4a25046f 100644 (file)
@@ -2,7 +2,7 @@
 
 <form (ngSubmit)="addFollowing()">
   <div class="form-group">
-    <label for="hosts">1 host (without "http://") per line</label>
+    <label i18n for="hosts">1 host (without "http://") per line</label>
 
     <textarea
       type="text" class="form-control" placeholder="example.com" id="hosts" name="hosts"
@@ -14,9 +14,9 @@
     </div>
   </div>
 
-  <div *ngIf="httpEnabled() === false"  class="alert alert-warning">
+  <div i18n *ngIf="httpEnabled() === false"  class="alert alert-warning">
     It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
   </div>
 
-  <input type="submit" value="Add following" [disabled]="hostsError || !hostsString" class="btn btn-default">
+  <input type="submit" i18n-value value="Add following" [disabled]="hostsError || !hostsString" class="btn btn-default">
 </form>
index c296c8852cbf15230952106dc3380c159cdbca51..f197c1fe9f3ad635b6ab7418e22dec18c9f20f7e 100644 (file)
@@ -4,6 +4,7 @@ import { NotificationsService } from 'angular2-notifications'
 import { ConfirmService } from '../../../core'
 import { validateHost } from '../../../shared'
 import { FollowService } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-following-add',
@@ -19,7 +20,8 @@ export class FollowingAddComponent {
     private router: Router,
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
-    private followService: FollowService
+    private followService: FollowService,
+    private i18n: I18n
   ) {}
 
   httpEnabled () {
@@ -34,7 +36,7 @@ export class FollowingAddComponent {
 
     for (const host of hosts) {
       if (validateHost(host) === false) {
-        newHostsErrors.push(`${host} is not valid`)
+        newHostsErrors.push(this.i18n('{{ host }} is not valid', { host }))
       }
     }
 
@@ -48,26 +50,26 @@ export class FollowingAddComponent {
 
     const hosts = this.getNotEmptyHosts()
     if (hosts.length === 0) {
-      this.error = 'You need to specify hosts to follow.'
+      this.error = this.i18n('You need to specify hosts to follow.')
     }
 
     if (!this.isHostsUnique(hosts)) {
-      this.error = 'Hosts need to be unique.'
+      this.error = this.i18n('Hosts need to be unique.')
       return
     }
 
-    const confirmMessage = 'If you confirm, you will send a follow request to:<br /> - ' + hosts.join('<br /> - ')
-    const res = await this.confirmService.confirm(confirmMessage, 'Follow new server(s)')
+    const confirmMessage = this.i18n('If you confirm, you will send a follow request to:<br /> - ') + hosts.join('<br /> - ')
+    const res = await this.confirmService.confirm(confirmMessage, this.i18n('Follow new server(s)'))
     if (res === false) return
 
     this.followService.follow(hosts).subscribe(
       () => {
-        this.notificationsService.success('Success', 'Follow request(s) sent!')
+        this.notificationsService.success(this.i18n('Success'), this.i18n('Follow request(s) sent!'))
 
         setTimeout(() => this.router.navigate([ '/admin/follows/following-list' ]), 500)
       },
 
-      err => this.notificationsService.error('Error', err.message)
+      err => this.notificationsService.error(this.i18n('Error'), err.message)
     )
   }
 
@@ -76,10 +78,8 @@ export class FollowingAddComponent {
   }
 
   private getNotEmptyHosts () {
-    const hosts = this.hostsString
+    return this.hostsString
       .split('\n')
       .filter(host => host && host.length !== 0) // Eject empty hosts
-
-    return hosts
   }
 }
index 24981d3e91e7c79e7fd9d5dbcb8b5e69005bd9dd..e4a45e88c44e7a38d9f1bf7232e0da56aeb08702 100644 (file)
@@ -4,10 +4,10 @@
 >
   <ng-template pTemplate="header">
     <tr>
-      <th style="width: 60px">ID</th>
-      <th>Host</th>
-      <th>State</th>
-      <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
+      <th i18n style="width: 60px">ID</th>
+      <th i18n>Host</th>
+      <th i18n>State</th>
+      <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
       <th></th>
     </tr>
   </ng-template>
index 873a5d96581f8ac87f9bb404a4cf5eb94ef2e496..2fb818c905e85256815386bc6b81c82618dd7f5a 100644 (file)
@@ -5,6 +5,7 @@ import { AccountFollow } from '../../../../../../shared/models/actors/follow.mod
 import { ConfirmService } from '../../../core/confirm/confirm.service'
 import { RestPagination, RestTable } from '../../../shared'
 import { FollowService } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-followers-list',
@@ -20,7 +21,8 @@ export class FollowingListComponent extends RestTable implements OnInit {
   constructor (
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
-    private followService: FollowService
+    private followService: FollowService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -30,16 +32,22 @@ export class FollowingListComponent extends RestTable implements OnInit {
   }
 
   async removeFollowing (follow: AccountFollow) {
-    const res = await this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow')
+    const res = await this.confirmService.confirm(
+      this.i18n('Do you really want to unfollow {{ host }}?', { host: follow.following.host }),
+      this.i18n('Unfollow')
+    )
     if (res === false) return
 
     this.followService.unfollow(follow).subscribe(
       () => {
-        this.notificationsService.success('Success', `You are not following ${follow.following.host} anymore.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('You are not following {{ host }} anymore.', { host: follow.following.host })
+        )
         this.loadData()
       },
 
-      err => this.notificationsService.error('Error', err.message)
+      err => this.notificationsService.error(this.i18n('Error'), err.message)
     )
   }
 
@@ -51,7 +59,7 @@ export class FollowingListComponent extends RestTable implements OnInit {
                           this.totalRecords = resultList.total
                         },
 
-                        err => this.notificationsService.error('Error', err.message)
+                        err => this.notificationsService.error(this.i18n('Error'), err.message)
                       )
   }
 }
index 71e82059cf6151a8276dc96f17db0eb4f9d1595f..a8258bf70a80b9c6d3546856bbcefd6ed20a0457 100644 (file)
@@ -1,5 +1,5 @@
 <div class="admin-sub-header">
-  <div class="form-sub-title">Manage follows</div>
+  <div i18n class="form-sub-title">Manage follows</div>
 
   <tabset #followsMenuTabs>
     <tab *ngFor="let link of links">
index 7b5271956748f47212403973d06232971eaba6ca..c0e0cc95dc16dd49345a26807f09d8b5bf86e273 100644 (file)
@@ -1 +1,4 @@
-export * from './'
+export * from './shared'
+export * from './jobs-list'
+export * from './job.routes'
+export * from './job.component'
index 0cc4dc3e0378cd75e5c2945916174907e57c1703..20c35cb5b7c49a154661c45ed9a57c7b16be1c62 100644 (file)
@@ -1,5 +1,5 @@
 <div class="admin-sub-header">
-  <div class="form-sub-title">Jobs list</div>
+  <div i18n class="form-sub-title">Jobs list</div>
 
   <div class="peertube-select-container">
     <select [(ngModel)]="jobState" (ngModelChange)="onJobStateChanged()">
   <ng-template pTemplate="header">
     <tr>
       <th style="width: 27px"></th>
-      <th style="width: 60px">ID</th>
-      <th style="width: 210px">Type</th>
-      <th style="width: 130px">State</th>
-      <th style="width: 250px" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
-      <th style="width: 250px">Updated</th>
+      <th i18n style="width: 60px">ID</th>
+      <th i18n style="width: 210px">Type</th>
+      <th i18n style="width: 130px">State</th>
+      <th i18n style="width: 250px" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
+      <th i18n style="width: 250px">Updated</th>
     </tr>
   </ng-template>
 
index ad2f05c6bea8447e56d1b15a5504737058f2a7d9..29dd9f31c3cad9f127c828ef410d35aa0e864f7d 100644 (file)
@@ -7,6 +7,7 @@ import { JobState } from '../../../../../../shared/models'
 import { RestPagination, RestTable } from '../../../shared'
 import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
 import { JobService } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-jobs-list',
@@ -27,7 +28,8 @@ export class JobsListComponent extends RestTable implements OnInit {
   constructor (
     private notificationsService: NotificationsService,
     private restExtractor: RestExtractor,
-    private jobsService: JobService
+    private jobsService: JobService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -51,7 +53,7 @@ export class JobsListComponent extends RestTable implements OnInit {
           this.totalRecords = resultList.total
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
index 578cd98c3362eb4e8efd979e87d06731d9c84d58..d8b00b86228fba4e25a4b1fab84dfdb03388b8b9 100644 (file)
@@ -7,6 +7,7 @@ import { Observable } from 'rxjs'
 import { ResultList, UserCreate, UserUpdate } from '../../../../../../shared'
 import { environment } from '../../../../environments/environment'
 import { RestExtractor, RestPagination, RestService, User } from '../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Injectable()
 export class UserService {
@@ -16,9 +17,9 @@ export class UserService {
   constructor (
     private authHttp: HttpClient,
     private restService: RestService,
-    private restExtractor: RestExtractor
-  ) {
-  }
+    private restExtractor: RestExtractor,
+    private i18n: I18n
+  ) { }
 
   addUser (userCreate: UserCreate) {
     return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
index 2a9882cdec779b7513af1c9f7031a4cc27c98896..b91ffa1151ce8438b9a6844f00999e2dc33aed93 100644 (file)
@@ -1,20 +1,13 @@
 import { Component, OnInit } from '@angular/core'
 import { FormBuilder, FormGroup } from '@angular/forms'
 import { Router } from '@angular/router'
-
 import { NotificationsService } from 'angular2-notifications'
-
 import { UserService } from '../shared'
-import {
-  USER_USERNAME,
-  USER_EMAIL,
-  USER_PASSWORD,
-  USER_VIDEO_QUOTA,
-  USER_ROLE
-} from '../../../shared'
+import { USER_EMAIL, USER_PASSWORD, USER_ROLE, USER_USERNAME, USER_VIDEO_QUOTA } from '../../../shared'
 import { ServerService } from '../../../core'
 import { UserCreate, UserRole } from '../../../../../../shared'
 import { UserEdit } from './user-edit'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-user-create',
@@ -45,7 +38,8 @@ export class UserCreateComponent extends UserEdit implements OnInit {
     private formBuilder: FormBuilder,
     private router: Router,
     private notificationsService: NotificationsService,
-    private userService: UserService
+    private userService: UserService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -76,7 +70,10 @@ export class UserCreateComponent extends UserEdit implements OnInit {
 
     this.userService.addUser(userCreate).subscribe(
       () => {
-        this.notificationsService.success('Success', `User ${userCreate.username} created.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('User {{ username }} created.', { username: userCreate.username })
+        )
         this.router.navigate([ '/admin/users/list' ])
       },
 
@@ -89,6 +86,6 @@ export class UserCreateComponent extends UserEdit implements OnInit {
   }
 
   getFormButtonTitle () {
-    return 'Create user'
+    return this.i18n('Create user')
   }
 }
index a8c0ddadb6cce89063471b1d287f5b86062b622b..4626a40c92ff832e1e0196b4d9a6f6290b381311 100644 (file)
@@ -1,13 +1,13 @@
-<div class="form-sub-title" *ngIf="isCreation() === true">Create user</div>
-<div class="form-sub-title" *ngIf="isCreation() === false">Edit user {{ username }}</div>
+<div i18n class="form-sub-title" *ngIf="isCreation() === true">Create user</div>
+<div i18n class="form-sub-title" *ngIf="isCreation() === false">Edit user {{ username }}</div>
 
 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
 
 <form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
   <div class="form-group" *ngIf="isCreation()">
-    <label for="username">Username</label>
+    <label i18n for="username">Username</label>
     <input
-      type="text" id="username" placeholder="john"
+      type="text" id="username" i18n-placeholder placeholder="john"
       formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
     >
     <div *ngIf="formErrors.username" class="form-error">
@@ -16,9 +16,9 @@
   </div>
 
   <div class="form-group">
-    <label for="email">Email</label>
+    <label i18n for="email">Email</label>
     <input
-      type="text" id="email" placeholder="mail@example.com"
+      type="text" id="email" i18n-placeholder placeholder="mail@example.com"
       formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
     >
     <div *ngIf="formErrors.email" class="form-error">
@@ -27,7 +27,7 @@
   </div>
 
   <div class="form-group" *ngIf="isCreation()">
-    <label for="password">Password</label>
+    <label i18n for="password">Password</label>
     <input
       type="password" id="password"
       formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
@@ -38,7 +38,7 @@
   </div>
 
   <div class="form-group">
-    <label for="role">Role</label>
+    <label i18n for="role">Role</label>
     <div class="peertube-select-container">
       <select id="role" formControlName="role">
         <option *ngFor="let role of roles" [value]="role.value">
@@ -53,7 +53,7 @@
   </div>
 
   <div class="form-group">
-    <label for="videoQuota">Video quota</label>
+    <label i18n for="videoQuota">Video quota</label>
     <div class="peertube-select-container">
       <select id="videoQuota" formControlName="videoQuota">
         <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
@@ -62,7 +62,7 @@
       </select>
     </div>
 
-    <div class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()">
+    <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()">
       Transcoding is enabled on server. The video quota only take in account <strong>original</strong> video. <br />
       At most, this user could use ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}.
     </div>
index 3cde07c653e680bf773e65090282847f545b555a..dca555706511e34fb6dabe016f56212e6c7a2a20 100644 (file)
@@ -8,6 +8,7 @@ import { User, USER_EMAIL, USER_ROLE, USER_VIDEO_QUOTA } from '../../../shared'
 import { ServerService } from '../../../core'
 import { UserEdit } from './user-edit'
 import { UserUpdate } from '../../../../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-user-update',
@@ -39,7 +40,8 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
     private router: Router,
     private notificationsService: NotificationsService,
     private formBuilder: FormBuilder,
-    private userService: UserService
+    private userService: UserService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -81,7 +83,10 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
 
     this.userService.updateUser(this.userId, userUpdate).subscribe(
       () => {
-        this.notificationsService.success('Success', `User ${this.username} updated.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('User {{ username }} updated.', { username: this.username })
+        )
         this.router.navigate([ '/admin/users/list' ])
       },
 
@@ -94,7 +99,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
   }
 
   getFormButtonTitle () {
-    return 'Update user'
+    return this.i18n('Update user')
   }
 
   private onUserFetched (userJson: User) {
index 09a4ac1e72be3f81f0592f7250604f9ddf1bce28..166fafef0ff8064dc4b899105d0fce2cae8a7a19 100644 (file)
@@ -1,9 +1,9 @@
 <div class="admin-sub-header">
-  <div class="form-sub-title">Users list</div>
+  <div i18n class="form-sub-title">Users list</div>
 
   <a class="add-button" routerLink="/admin/users/create">
     <span class="icon icon-add"></span>
-    Create user
+    <ng-container i18n>Create user</ng-container>
   </a>
 </div>
 
 >
   <ng-template pTemplate="header">
     <tr>
-      <th pSortableColumn="username">Username <p-sortIcon field="username"></p-sortIcon></th>
-      <th>Email</th>
-      <th>Video quota</th>
-      <th>Role</th>
-      <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
+      <th i18n pSortableColumn="username">Username <p-sortIcon field="username"></p-sortIcon></th>
+      <th i18n>Email</th>
+      <th i18n>Video quota</th>
+      <th i18n>Role</th>
+      <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
       <th></th>
     </tr>
   </ng-template>
index 2cc4d4349eae118cc6194481348fb43ed5d30fe5..b644fcf71962a445fd66544f343533fb8eac957c 100644 (file)
@@ -1,11 +1,10 @@
 import { Component, OnInit } from '@angular/core'
-
 import { NotificationsService } from 'angular2-notifications'
 import { SortMeta } from 'primeng/components/common/sortmeta'
-
 import { ConfirmService } from '../../../core'
 import { RestPagination, RestTable, User } from '../../../shared'
 import { UserService } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-user-list',
@@ -22,7 +21,8 @@ export class UserListComponent extends RestTable implements OnInit {
   constructor (
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
-    private userService: UserService
+    private userService: UserService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -33,20 +33,23 @@ export class UserListComponent extends RestTable implements OnInit {
 
   async removeUser (user: User) {
     if (user.username === 'root') {
-      this.notificationsService.error('Error', 'You cannot delete root.')
+      this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot delete root.'))
       return
     }
 
-    const res = await this.confirmService.confirm('Do you really want to delete this user?', 'Delete')
+    const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this user?'), this.i18n('Delete'))
     if (res === false) return
 
     this.userService.removeUser(user).subscribe(
       () => {
-        this.notificationsService.success('Success', `User ${user.username} deleted.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('User {{ username }} deleted.', { username: user.username })
+        )
         this.loadData()
       },
 
-      err => this.notificationsService.error('Error', err.message)
+      err => this.notificationsService.error(this.i18n('Error'), err.message)
     )
   }
 
@@ -62,7 +65,7 @@ export class UserListComponent extends RestTable implements OnInit {
                         this.totalRecords = resultList.total
                       },
 
-                      err => this.notificationsService.error('Error', err.message)
+                      err => this.notificationsService.error(this.i18n('Error'), err.message)
                     )
   }
 }
index 5f70db991afb358823bb94a4845153fd8a63ebb1..8111e5f73f0b306c9db083edf021cdb730087c90 100644 (file)
@@ -1,5 +1,5 @@
 <div class="admin-sub-header">
-  <div class="form-sub-title">Video abuses list</div>
+  <div i18n class="form-sub-title">Video abuses list</div>
 </div>
 
 <p-table
@@ -8,10 +8,10 @@
 >
   <ng-template pTemplate="header">
     <tr>
-      <th>Reason</th>
-      <th>Reporter</th>
-      <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
-      <th>Video</th>
+      <th i18n>Reason</th>
+      <th i18n>Reporter</th>
+      <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
+      <th i18n>Video</th>
     </tr>
   </ng-template>
 
     <tr>
       <td>{{ videoAbuse.reason }}</td>
       <td>
-        <a [href]="videoAbuse.reporterAccount.url" title="Go to the account" target="_blank" rel="noopener noreferrer">
+        <a [href]="videoAbuse.reporterAccount.url" i18n-title title="Go to the account" target="_blank" rel="noopener noreferrer">
           {{ createByString(videoAbuse.reporterAccount) }}
         </a>
       </td>
       <td>{{ videoAbuse.createdAt }}</td>
       <td>
-        <a [href]="videoAbuse.video.url" title="Go to the video" target="_blank" rel="noopener noreferrer">
+        <a [href]="videoAbuse.video.url" i18n-title title="Go to the video" target="_blank" rel="noopener noreferrer">
           {{ videoAbuse.video.name }}
         </a>
       </td>
index b650194b76bae3cbba951b9a057cf1dba6b60f20..6ddebff7e8263bc9e6acd35207b137c6e83351de 100644 (file)
@@ -5,6 +5,7 @@ import { SortMeta } from 'primeng/components/common/sortmeta'
 import { VideoAbuse } from '../../../../../../shared'
 
 import { RestPagination, RestTable, VideoAbuseService } from '../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-abuse-list',
@@ -20,7 +21,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
 
   constructor (
     private notificationsService: NotificationsService,
-    private videoAbuseService: VideoAbuseService
+    private videoAbuseService: VideoAbuseService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -41,7 +43,7 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
                    this.totalRecords = resultList.total
                  },
 
-                 err => this.notificationsService.error('Error', err.message)
+                 err => this.notificationsService.error(this.i18n('Error'), err.message)
                )
   }
 }
index 0a0fcb762bcc074d540e1d69a0002545fc111a16..04f0e3b5c243479dacc80e68f3e8f219cf88a242 100644 (file)
@@ -1,5 +1,5 @@
 <div class="admin-sub-header">
-  <div class="form-sub-title">Blacklisted videos</div>
+  <div i18n class="form-sub-title">Blacklisted videos</div>
 </div>
 
 <p-table
@@ -8,12 +8,12 @@
 >
   <ng-template pTemplate="header">
     <tr>
-      <th pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th>
-      <th>Description</th>
-      <th pSortableColumn="views">Views <p-sortIcon field="views"></p-sortIcon></th>
-      <th>NSFW</th>
-      <th>UUID</th>
-      <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
+      <th i18n pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th>
+      <th i18n>Description</th>
+      <th i18n pSortableColumn="views">Views <p-sortIcon field="views"></p-sortIcon></th>
+      <th i18n>NSFW</th>
+      <th i18n>UUID</th>
+      <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
       <th></th>
     </tr>
   </ng-template>
@@ -27,7 +27,7 @@
       <td>{{ videoBlacklist.uuid }}</td>
       <td>{{ videoBlacklist.createdAt }}</td>
       <td class="action-cell">
-        <my-delete-button label="Unblacklist" (click)="removeVideoFromBlacklist(videoBlacklist)"></my-delete-button>
+        <my-delete-button i18n-label label="Unblacklist" (click)="removeVideoFromBlacklist(videoBlacklist)"></my-delete-button>
       </td>
     </tr>
   </ng-template>
index 7210e677c27d1deacef10cbdaf5a8aa4afb3ad37..1864e5f650d6a46b572451024c6138529c623c98 100644 (file)
@@ -1,11 +1,10 @@
 import { Component, OnInit } from '@angular/core'
 import { SortMeta } from 'primeng/components/common/sortmeta'
-
 import { NotificationsService } from 'angular2-notifications'
-
 import { ConfirmService } from '../../../core'
-import { VideoBlacklistService, RestTable, RestPagination } from '../../../shared'
+import { RestPagination, RestTable, VideoBlacklistService } from '../../../shared'
 import { BlacklistedVideo } from '../../../../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-blacklist-list',
@@ -22,7 +21,8 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
   constructor (
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
-    private videoBlacklistService: VideoBlacklistService
+    private videoBlacklistService: VideoBlacklistService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -32,18 +32,23 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
   }
 
   async removeVideoFromBlacklist (entry: BlacklistedVideo) {
-    const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the videos list.'
+    const confirmMessage = this.i18n(
+      'Do you really want to remove this video from the blacklist ? It will be available again in the videos list.'
+    )
 
-    const res = await this.confirmService.confirm(confirmMessage, 'Unblacklist')
+    const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblacklist'))
     if (res === false) return
 
     this.videoBlacklistService.removeVideoFromBlacklist(entry.videoId).subscribe(
       () => {
-        this.notificationsService.success('Success', `Video ${entry.name} removed from the blacklist.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('Video {{ name }} removed from the blacklist.', { name: entry.name })
+        )
         this.loadData()
       },
 
-      err => this.notificationsService.error('Error', err.message)
+      err => this.notificationsService.error(this.i18n('Error'), err.message)
     )
   }
 
@@ -55,7 +60,7 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
           this.totalRecords = resultList.total
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 }
index b0e3cada4390865ccf33fa40ea77a73c046df8f2..767ef0336076719e09c881ae6ffe0d9ccf8eaf26 100644 (file)
@@ -2,9 +2,9 @@
 
 <form role="form" (ngSubmit)="changePassword()" [formGroup]="form">
 
-  <label for="new-password">Change password</label>
+  <label i18n for="new-password">Change password</label>
   <input
-    type="password" id="new-password" placeholder="New password"
+    type="password" id="new-password" i18n-placeholder placeholder="New password"
     formControlName="new-password" [ngClass]="{ 'input-error': formErrors['new-password'] }"
   >
   <div *ngIf="formErrors['new-password']" class="form-error">
@@ -12,9 +12,9 @@
   </div>
 
   <input
-    type="password" id="new-confirmed-password" placeholder="Confirm new password"
+    type="password" id="new-confirmed-password" i18n-placeholder placeholder="Confirm new password"
     formControlName="new-confirmed-password"
   >
 
-  <input type="submit" value="Change password" [disabled]="!form.valid">
+  <input type="submit" i18n-value value="Change password" [disabled]="!form.valid">
 </form>
index 80af668f96c46218e75eee06416f3be7df57cc15..1a88aa82e38afaef4f87386943fe80c51346cd87 100644 (file)
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'
 import { FormBuilder, FormGroup } from '@angular/forms'
 import { NotificationsService } from 'angular2-notifications'
 import { FormReactive, USER_PASSWORD, UserService } from '../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-change-password',
@@ -24,7 +25,8 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
   constructor (
     private formBuilder: FormBuilder,
     private notificationsService: NotificationsService,
-    private userService: UserService
+    private userService: UserService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -49,12 +51,12 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
     this.error = null
 
     if (newPassword !== newConfirmedPassword) {
-      this.error = 'The new password and the confirmed password do not correspond.'
+      this.error = this.i18n('The new password and the confirmed password do not correspond.')
       return
     }
 
     this.userService.changePassword(newPassword).subscribe(
-      () => this.notificationsService.success('Success', 'Password updated.'),
+      () => this.notificationsService.success(this.i18n('Success'), this.i18n('Password updated.')),
 
       err => this.error = err.message
     )
index 306f3a12c83817d9207d1732a0fdb5aeb7769de3..bbdce5b024dfac7c5ad4a5ec6f3f8995921c9590 100644 (file)
@@ -2,7 +2,7 @@
 
 <form role="form" (ngSubmit)="updateMyProfile()" [formGroup]="form">
 
-  <label for="display-name">Display name</label>
+  <label i18n for="display-name">Display name</label>
   <input
     type="text" id="display-name"
     formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
@@ -11,7 +11,7 @@
     {{ formErrors['display-name'] }}
   </div>
 
-  <label for="description">Description</label>
+  <label i18n for="description">Description</label>
   <textarea
     id="description" formControlName="description"
     [ngClass]="{ 'input-error': formErrors['description'] }"
@@ -20,5 +20,5 @@
     {{ formErrors.description }}
   </div>
 
-  <input type="submit" value="Update my profile" [disabled]="!form.valid">
+  <input type="submit" i18n-value value="Update my profile" [disabled]="!form.valid">
 </form>
index 468be022c905c17e7b95b07219cd466935dcd057..35843ecd92899a535ae9c9b26d2aa13773fa9db9 100644 (file)
@@ -3,6 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms'
 import { NotificationsService } from 'angular2-notifications'
 import { FormReactive, USER_DESCRIPTION, USER_DISPLAY_NAME, UserService } from '../../../shared'
 import { User } from '@app/shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-profile',
@@ -27,7 +28,8 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
   constructor (
     private formBuilder: FormBuilder,
     private notificationsService: NotificationsService,
-    private userService: UserService
+    private userService: UserService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -56,7 +58,7 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
         this.user.account.displayName = displayName
         this.user.account.description = description
 
-        this.notificationsService.success('Success', 'Profile updated.')
+        this.notificationsService.success(this.i18n('Success'), this.i18n('Profile updated.'))
       },
 
       err => this.error = err.message
index 0fcc7782eabba17f90c94057ac4b1947da6ceb1e..056c2a7d76b26f88d8eca3307d654090ce03e46b 100644 (file)
@@ -6,27 +6,27 @@
       <div class="user-info-display-name">{{ user.account.displayName }}</div>
       <div class="user-info-username">{{ user.username }}</div>
     </div>
-    <div class="user-info-followers">{{ user.account?.followersCount }} subscribers</div>
+    <div i18n class="user-info-followers">{{ user.account?.followersCount }} subscribers</div>
   </div>
 </div>
 
 <div class="button-file">
-  <span>Change your avatar</span>
+  <span i18n>Change your avatar</span>
   <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="changeAvatar()" />
 </div>
-<div class="file-max-size">(extensions: {{ avatarExtensions }}, max size: {{ maxAvatarSize | bytes }})</div>
+<div i18n class="file-max-size">(extensions: {{ avatarExtensions }}, max size: {{ maxAvatarSize | bytes }})</div>
 
 <div class="user-quota">
-  <span class="user-quota-label">Video quota:</span> {{ userVideoQuotaUsed | bytes: 0 }} / {{ userVideoQuota }}
+  <span i18n class="user-quota-label">Video quota:</span> {{ userVideoQuotaUsed | bytes: 0 }} / {{ userVideoQuota }}
 </div>
 
 <ng-template [ngIf]="user && user.account">
-  <div class="account-title">Profile</div>
+  <div i18n class="account-title">Profile</div>
   <my-account-profile [user]="user"></my-account-profile>
 </ng-template>
 
-<div class="account-title">Password</div>
+<div i18n class="account-title">Password</div>
 <my-account-change-password></my-account-change-password>
 
-<div class="account-title">Video settings</div>
+<div i18n class="account-title">Video settings</div>
 <my-account-video-settings [user]="user"></my-account-video-settings>
index 06d1138e72979fb81915cbf335397c2b1ebabbd3..44eddaa7c5a76066d83eaaef911d118c44344d76 100644 (file)
@@ -5,6 +5,7 @@ import { AuthService } from '../../core'
 import { ServerService } from '../../core/server'
 import { User } from '../../shared'
 import { UserService } from '../../shared/users'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-settings',
@@ -22,7 +23,8 @@ export class MyAccountSettingsComponent implements OnInit {
     private userService: UserService,
     private authService: AuthService,
     private serverService: ServerService,
-    private notificationsService: NotificationsService
+    private notificationsService: NotificationsService,
+    private i18n: I18n
   ) {}
 
   ngOnInit () {
@@ -33,7 +35,7 @@ export class MyAccountSettingsComponent implements OnInit {
         if (this.user.videoQuota !== -1) {
           this.userVideoQuota = new BytesPipe().transform(this.user.videoQuota, 0).toString()
         } else {
-          this.userVideoQuota = 'Unlimited'
+          this.userVideoQuota = this.i18n('Unlimited')
         }
       }
     )
@@ -51,12 +53,12 @@ export class MyAccountSettingsComponent implements OnInit {
     this.userService.changeAvatar(formData)
       .subscribe(
         data => {
-          this.notificationsService.success('Success', 'Avatar changed.')
+          this.notificationsService.success(this.i18n('Success'), this.i18n('Avatar changed.'))
 
           this.user.account.avatar = data.avatar
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
index 0e8598e9e8de1107fc8a76e70a50f0e5bf362b83..98587eb18505a26917f8d624776e7ecc9e5111f7 100644 (file)
@@ -1,13 +1,16 @@
 <form role="form" (ngSubmit)="updateDetails()" [formGroup]="form">
   <div class="form-group">
-    <label for="nsfwPolicy">Default policy on videos containing sensitive content</label>
-    <my-help helpType="custom" customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."></my-help>
+    <label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label>
+    <my-help
+      helpType="custom" i18n-customHtml
+      customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."
+    ></my-help>
 
     <div class="peertube-select-container">
       <select id="nsfwPolicy" formControlName="nsfwPolicy">
-        <option value="do_not_list">Do not list</option>
-        <option value="blur">Blur thumbnails</option>
-        <option value="display">Display</option>
+        <option i18n value="do_not_list">Do not list</option>
+        <option i18n value="blur">Blur thumbnails</option>
+        <option i18n value="display">Display</option>
       </select>
     </div>
   </div>
@@ -18,8 +21,8 @@
       formControlName="autoPlayVideo"
     >
     <label for="autoPlayVideo"></label>
-    <label for="autoPlayVideo">Automatically plays video</label>
+    <label i18n for="autoPlayVideo">Automatically plays video</label>
   </div>
 
-  <input type="submit" value="Save" [disabled]="!form.valid">
+  <input type="submit" i18n-value value="Save" [disabled]="!form.valid">
 </form>
index acc70c14d7f833c02d2ba32d96cece1cbe77ec9a..4588f73db46ff5069b930790ad008fcde572f781 100644 (file)
@@ -4,6 +4,7 @@ import { NotificationsService } from 'angular2-notifications'
 import { UserUpdateMe } from '../../../../../../shared'
 import { AuthService } from '../../../core'
 import { FormReactive, User, UserService } from '../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-video-settings',
@@ -21,7 +22,8 @@ export class MyAccountVideoSettingsComponent extends FormReactive implements OnI
     private authService: AuthService,
     private formBuilder: FormBuilder,
     private notificationsService: NotificationsService,
-    private userService: UserService
+    private userService: UserService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -49,12 +51,12 @@ export class MyAccountVideoSettingsComponent extends FormReactive implements OnI
 
     this.userService.updateMyProfile(details).subscribe(
       () => {
-        this.notificationsService.success('Success', 'Information updated.')
+        this.notificationsService.success(this.i18n('Success'), this.i18n('Information updated.'))
 
         this.authService.refreshUserInformation()
       },
 
-      err => this.notificationsService.error('Error', err.message)
+      err => this.notificationsService.error(this.i18n('Error'), err.message)
     )
   }
 }
index c82bb39c805b64d0f837c6b9d306a9f64209e7b4..9b5a12d18b63d7579c64537e5e73ce0e379f01d8 100644 (file)
@@ -11,6 +11,7 @@ import {
 } from '@app/shared/forms/form-validators/video-channel'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
 import { AuthService } from '@app/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-video-channel-create',
@@ -37,7 +38,8 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
     private notificationsService: NotificationsService,
     private router: Router,
     private formBuilder: FormBuilder,
-    private videoChannelService: VideoChannelService
+    private videoChannelService: VideoChannelService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -69,7 +71,10 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
     this.videoChannelService.createVideoChannel(videoChannelCreate).subscribe(
       () => {
         this.authService.refreshUserInformation()
-        this.notificationsService.success('Success', `Video channel ${videoChannelCreate.displayName} created.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('Video channel {{ videoChannelName }} created.', { videoChannelName: videoChannelCreate.displayName })
+        )
         this.router.navigate([ '/my-account', 'video-channels' ])
       },
 
@@ -82,6 +87,6 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
   }
 
   getFormButtonTitle () {
-    return 'Create'
+    return this.i18n('Create')
   }
 }
index 10d408d55be9f7fe36f625bbf89ec89d4098d9f8..1c08cfdca3a0074510c8065a58f5a5335a07f05a 100644 (file)
@@ -1,11 +1,11 @@
-<div class="form-sub-title" *ngIf="isCreation() === true">Create a video channel</div>
-<div class="form-sub-title" *ngIf="isCreation() === false">Update {{ videoChannel?.displayName }}</div>
+<div i18n class="form-sub-title" *ngIf="isCreation() === true">Create a video channel</div>
+<div i18n class="form-sub-title" *ngIf="isCreation() === false">Update {{ videoChannel?.displayName }}</div>
 
 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
 
 <form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
   <div class="form-group">
-    <label for="display-name">Display name</label>
+    <label i18n for="display-name">Display name</label>
     <input
       type="text" id="display-name"
       formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
@@ -16,7 +16,7 @@
   </div>
 
   <div class="form-group">
-    <label for="description">Description</label>
+    <label i18n for="description">Description</label>
     <textarea
       id="description" formControlName="description"
       [ngClass]="{ 'input-error': formErrors['description'] }"
@@ -29,7 +29,7 @@
   <div class="form-group">
     <label for="support">Support</label>
     <my-help
-      helpType="markdownEnhanced" preHtml="Short text to tell people how they can support your channel (membership platform...).<br /><br />
+      helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support your channel (membership platform...).<br /><br />
 When you will upload a video in this channel, the video support field will be automatically filled by this text."
     ></my-help>
     <my-markdown-textarea
index b4c8df3cd7a106c309d0afd8ebc42586b81e90e4..78c57876418856eda80b79c2cdb5eb2897ea4552 100644 (file)
@@ -13,6 +13,7 @@ import { VideoChannelService } from '@app/shared/video-channel/video-channel.ser
 import { Subscription } from 'rxjs'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
 import { AuthService } from '@app/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-video-channel-update',
@@ -43,7 +44,8 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
     private router: Router,
     private route: ActivatedRoute,
     private formBuilder: FormBuilder,
-    private videoChannelService: VideoChannelService
+    private videoChannelService: VideoChannelService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -97,7 +99,10 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
     this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.uuid, videoChannelUpdate).subscribe(
       () => {
         this.authService.refreshUserInformation()
-        this.notificationsService.success('Success', `Video channel ${videoChannelUpdate.displayName} updated.`)
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('Video channel {{ videoChannelName }} updated.', { videoChannelName: videoChannelUpdate.displayName })
+        )
         this.router.navigate([ '/my-account', 'video-channels' ])
       },
 
@@ -110,6 +115,6 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
   }
 
   getFormButtonTitle () {
-    return 'Update'
+    return this.i18n('Update')
   }
 }
index 90c401bc5d6b56cf4889f9448125e3063bc821ff..d27c3b4ec6c722c1b734bd56d7272e0e7b599cf8 100644 (file)
@@ -1,7 +1,7 @@
 <div class="video-channels-header">
   <a class="create-button" routerLink="create">
     <span class="icon icon-add"></span>
-    Create another video channel
+    <ng-container i18n>Create another video channel</ng-container>
   </a>
 </div>
 
     </a>
 
     <div class="video-channel-info">
-      <a [routerLink]="[ '/video-channels', videoChannel.uuid ]" class="video-channel-names" title="Go to the channel">
+      <a [routerLink]="[ '/video-channels', videoChannel.uuid ]" class="video-channel-names" i18n-title title="Go to the channel">
         <div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
         <!-- Hide the name for now, because it's an UUID not very friendly -->
         <!--<div class="video-channel-name">{{ videoChannel.name }}</div>-->
       </a>
 
-      <div class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
+      <div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div>
     </div>
 
     <div class="video-channel-buttons">
index 20c8798d15c340f5f6aa11fa1468aaca6facc277..cff1041f6cabba119dfbde055c5ab570a225b3d4 100644 (file)
@@ -6,6 +6,7 @@ import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
 import { User } from '@app/shared'
 import { flatMap } from 'rxjs/operators'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-video-channels',
@@ -21,7 +22,8 @@ export class MyAccountVideoChannelsComponent implements OnInit {
     private authService: AuthService,
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
-    private videoChannelService: VideoChannelService
+    private videoChannelService: VideoChannelService,
+    private i18n: I18n
   ) {}
 
   ngOnInit () {
@@ -32,10 +34,13 @@ export class MyAccountVideoChannelsComponent implements OnInit {
 
   async deleteVideoChannel (videoChannel: VideoChannel) {
     const res = await this.confirmService.confirmWithInput(
-      `Do you really want to delete ${videoChannel.displayName}? It will delete all videos uploaded in this channel too.`,
-      'Please type the name of the video channel to confirm',
+      this.i18n(
+        'Do you really want to delete {{ videoChannelName }}? It will delete all videos uploaded in this channel too.',
+        { videoChannelName: videoChannel.displayName }
+      ),
+      this.i18n('Please type the name of the video channel to confirm'),
       videoChannel.displayName,
-      'Delete'
+      this.i18n('Delete')
     )
     if (res === false) return
 
@@ -43,10 +48,13 @@ export class MyAccountVideoChannelsComponent implements OnInit {
       .subscribe(
         status => {
           this.loadVideoChannels()
-          this.notificationsService.success('Success', `Video channel ${videoChannel.name} deleted.`)
+          this.notificationsService.success(
+            this.i18n('Success'),
+            this.i18n('Video channel {{ videoChannelName } deleted.', { videoChannelName: videoChannel.displayName })
+          )
         },
 
-        error => this.notificationsService.error('Error', error.message)
+        error => this.notificationsService.error(this.i18n('Error'), error.message)
       )
   }
 
index a31cb0c3d8e65cedf50f2a19fa305addc72ca383..35a99d0b3ee32614c42831934cef0380dd2503fa 100644 (file)
@@ -1,4 +1,4 @@
-<div *ngIf="pagination.totalItems === 0">No results.</div>
+<div i18n *ngIf="pagination.totalItems === 0">No results.</div>
 
 <div
   myInfiniteScroller
 
       <div class="video-info">
         <a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
-        <span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
+        <span i18n class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
         <div class="video-info-private">{{ video.privacy.label }}</div>
       </div>
 
       <!-- Display only once -->
       <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0 && j === 0">
         <div class="action-selection-mode-child">
-          <span class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
+          <span i18n class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
             Cancel
           </span>
 
-          <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
+          <span i18n class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
             <span class="icon icon-delete-white"></span>
             Delete
           </span>
index 6ab6c2aa56a2eab0db31655567b7b0e22ef6cfcd..eed4be01f8ae0f4549445a86568ed74fde687754 100644 (file)
@@ -11,6 +11,7 @@ import { ConfirmService } from '../../core/confirm'
 import { AbstractVideoList } from '../../shared/video/abstract-video-list'
 import { Video } from '../../shared/video/video.model'
 import { VideoService } from '../../shared/video/video.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-account-videos',
@@ -18,7 +19,7 @@ import { VideoService } from '../../shared/video/video.service'
   styleUrls: [ './my-account-videos.component.scss' ]
 })
 export class MyAccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
-  titlePage = 'My videos'
+  titlePage: string
   currentRoute = '/my-account/videos'
   checkedVideos: { [ id: number ]: boolean } = {}
   pagination: ComponentPagination = {
@@ -30,14 +31,19 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
   protected baseVideoWidth = -1
   protected baseVideoHeight = 155
 
-  constructor (protected router: Router,
-               protected route: ActivatedRoute,
-               protected authService: AuthService,
-               protected notificationsService: NotificationsService,
-               protected confirmService: ConfirmService,
-               protected location: Location,
-               private videoService: VideoService) {
+  constructor (
+    protected router: Router,
+    protected route: ActivatedRoute,
+    protected authService: AuthService,
+    protected notificationsService: NotificationsService,
+    protected confirmService: ConfirmService,
+    protected location: Location,
+    protected i18n: I18n,
+    private videoService: VideoService
+  ) {
     super()
+
+    this.titlePage = this.i18n('My videos')
   }
 
   ngOnInit () {
index 591d58cf92c13a91b48dce21bcfd36f504312686..48db55ad3eb2e37e21a2133d39c92c7e51b73c7b 100644 (file)
@@ -1,10 +1,10 @@
 <div class="row">
   <div class="sub-menu">
-    <a routerLink="/my-account/settings" routerLinkActive="active" class="title-page">My settings</a>
+    <a i18n routerLink="/my-account/settings" routerLinkActive="active" class="title-page">My settings</a>
 
-    <a routerLink="/my-account/video-channels" routerLinkActive="active" class="title-page">My video channels</a>
+    <a i18n routerLink="/my-account/video-channels" routerLinkActive="active" class="title-page">My video channels</a>
 
-    <a routerLink="/my-account/videos" routerLinkActive="active" class="title-page">My videos</a>
+    <a i18n routerLink="/my-account/videos" routerLinkActive="active" class="title-page">My videos</a>
   </div>
 
   <div class="margin-content">
index 66aa2aec7c9e8139d4d5c90a5c1f6f192eba5012..2934003ab9aa50666d355cf8caa2f0032714c087 100644 (file)
@@ -1,3 +1,3 @@
-<div>
+<div i18n>
   Sorry, but we couldn't find the page you were looking for.
 </div>
\ No newline at end of file
index a4338121f488094d49a04b20395db095a16aeafe..b7125ff71c869abe45941add683d3fe8ab955b28 100644 (file)
@@ -1,20 +1,20 @@
 <div *ngIf="videoChannel" class="row">
   <div class="description col-md-6 col-sm-12">
     <div class="block">
-      <div class="small-title">Description</div>
+      <div i18n class="small-title">Description</div>
       <div class="content">{{ getVideoChannelDescription() }}</div>
     </div>
 
     <div class="block" *ngIf="videoChannel.support">
-      <div class="small-title">Support this channel</div>
+      <div i18n class="small-title">Support this channel</div>
       <div class="content">{{ videoChannel.support }}</div>
     </div>
   </div>
 
   <div class="stats col-md-6 col-sm-12">
     <div class="block">
-      <div class="small-title">Stats</div>
-      <div class="content">Created {{ videoChannel.createdAt | date }}</div>
+      <div i18n class="small-title">Stats</div>
+      <div i18n class="content">Created {{ videoChannel.createdAt | date }}</div>
     </div>
   </div>
 </div>
\ No newline at end of file
index 6f862718f22acfb0e0cefbbe17a3927a423c2b19..c5fd442c6c4663b0e7e07fcba3e5f05b2d09af56 100644 (file)
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'
 import { ActivatedRoute } from '@angular/router'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-channel-about',
@@ -12,7 +13,8 @@ export class VideoChannelAboutComponent implements OnInit {
   videoChannel: VideoChannel
 
   constructor (
-    protected route: ActivatedRoute,
+    private route: ActivatedRoute,
+    private i18n: I18n,
     private videoChannelService: VideoChannelService
   ) { }
 
@@ -25,6 +27,6 @@ export class VideoChannelAboutComponent implements OnInit {
   getVideoChannelDescription () {
     if (this.videoChannel.description) return this.videoChannel.description
 
-    return 'No description'
+    return this.i18n('No description')
   }
 }
index c9e72e512d63bc96a10a2653164801e03496b223..22239d75beddce296064fa340f0f6ee8a8da9d54 100644 (file)
@@ -10,6 +10,7 @@ import { VideoService } from '../../shared/video/video.service'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
 import { tap } from 'rxjs/operators'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-channel-videos',
@@ -20,7 +21,7 @@ import { tap } from 'rxjs/operators'
   ]
 })
 export class VideoChannelVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
-  titlePage = 'Published videos'
+  titlePage: string
   marginContent = false // Disable margin
   currentRoute = '/video-channel/videos'
   loadOnInit = false
@@ -34,10 +35,13 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
     protected notificationsService: NotificationsService,
     protected confirmService: ConfirmService,
     protected location: Location,
+    protected i18n: I18n,
     private videoChannelService: VideoChannelService,
     private videoService: VideoService
   ) {
     super()
+
+    this.titlePage = this.i18n('Published videos')
   }
 
   ngOnInit () {
@@ -63,7 +67,11 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
 
     return this.videoService
                .getVideoChannelVideos(this.videoChannel, newPagination, this.sort)
-               .pipe(tap(({ totalVideos }) => this.titlePage = `Published ${totalVideos} videos`))
+               .pipe(
+                 tap(({ totalVideos }) => {
+                   this.titlePage = this.i18n('Published {{ totalVideos }} videos', { totalVideos })
+                 })
+               )
   }
 
   generateSyndicationList () {
index 6b25d16ab7cf6ca2d21546acd168a8969810298a..a52894cac2b2f01235690a9384e9ce6a9deba5a3 100644 (file)
@@ -8,19 +8,19 @@
         <div class="actor-names">
           <div class="actor-display-name">{{ videoChannel.displayName }}</div>
         </div>
-        <div class="actor-followers">{{ videoChannel.followersCount }} subscribers</div>
+        <div i18n class="actor-followers">{{ videoChannel.followersCount }} subscribers</div>
 
-        <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" title="Go the owner account page" class="actor-owner">
-          <span>Created by {{ videoChannel.ownerBy }}</span>
+        <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n-title title="Go the owner account page" class="actor-owner">
+          <span i18n>Created by {{ videoChannel.ownerBy }}</span>
           <img [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" />
         </a>
       </div>
     </div>
 
     <div class="links">
-      <a routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
+      <a i18n routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
 
-      <a routerLink="about" routerLinkActive="active" class="title-page">About</a>
+      <a i18n routerLink="about" routerLinkActive="active" class="title-page">About</a>
     </div>
   </div>
 
index 6fa856742fb46108fcc438a887c648ccd562e38d..22d3c9a3642cc9ffa5c695c54ca18f1941c3f6c1 100644 (file)
@@ -1,5 +1,5 @@
 <div class="margin-content">
-  <div class="title-page title-page-single">
+  <div i18n class="title-page title-page-single">
     Welcome to the {{ instanceName }} instance
   </div>
 
@@ -8,41 +8,41 @@
   </div>
 
   <div class="description">
-    <div class="section-title">Description</div>
+    <div i18n class="section-title">Description</div>
 
     <div [innerHTML]="descriptionHTML"></div>
   </div>
 
   <div class="terms">
-    <div class="section-title">Terms</div>
+    <div i18n class="section-title">Terms</div>
 
     <div [innerHTML]="termsHTML"></div>
   </div>
 
   <div class="signup">
-    <div class="section-title">Signup</div>
+    <div i18n class="section-title">Signup</div>
 
     <div *ngIf="isSignupAllowed">
-      User registration is allowed and
+      <ng-container i18n>User registration is allowed and</ng-container>
 
-      <ng-template [ngIf]="userVideoQuota !== -1">
+      <ng-container i18n *ngIf="userVideoQuota !== -1">
         this instance provides a baseline quota of {{ userVideoQuota | bytes: 0 }} space for the videos of its users.
-      </ng-template>
+      </ng-container>
 
-      <ng-template [ngIf]="userVideoQuota === -1">
+      <ng-container i18n *ngIf="userVideoQuota === -1">
         this instance provides unlimited space for the videos of its users.
-      </ng-template>
+      </ng-container>
     </div>
 
-    <div *ngIf="isSignupAllowed === false">
+    <div i18n *ngIf="isSignupAllowed === false">
       User registration is currently not allowed.
     </div>
   </div>
 
   <div id="p2p-privacy">
-    <div class="section-title">P2P & Privacy</div>
+    <div i18n class="section-title">P2P & Privacy</div>
 
-    <p>
+    <p i18n>
       PeerTube uses the BitTorrent protocol to share bandwidth between users. It implies that your public IP address is stored in the public BitTorrent tracker of the video PeerTube instance as long as you're watching the video.
       If you want to keep your public IP address private, please use a VPN or Tor.
     </p>
index 3948d5c46bbb022a40dba6b74c38c14a76609163..c37b9318bef21ad23b1836fad39aca9fb79d2a37 100644 (file)
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'
 import { ServerService } from '@app/core'
 import { MarkdownService } from '@app/videos/shared'
 import { NotificationsService } from 'angular2-notifications'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-about',
@@ -17,7 +18,8 @@ export class AboutComponent implements OnInit {
   constructor (
     private notificationsService: NotificationsService,
     private serverService: ServerService,
-    private markdownService: MarkdownService
+    private markdownService: MarkdownService,
+    private i18n: I18n
   ) {}
 
   get instanceName () {
@@ -41,7 +43,7 @@ export class AboutComponent implements OnInit {
           this.termsHTML = this.markdownService.textMarkdownToHTML(res.instance.terms)
         },
 
-        err => this.notificationsService.error('Error getting about from server', err)
+        err => this.notificationsService.error(this.i18n('Error getting about from server'), err)
       )
   }
 
index 614d38d08b8c7ac7509ec37c15552e9c7d664b02..363f58155e7f277871a128d409daf0b75d0ae272 100644 (file)
@@ -1,5 +1,5 @@
 import { Observable, ReplaySubject, Subject, throwError as observableThrowError } from 'rxjs'
-import { catchError, map, mergeMap, tap, share } from 'rxjs/operators'
+import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
 import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
 import { Injectable } from '@angular/core'
 import { Router } from '@angular/router'
@@ -13,6 +13,7 @@ import { AuthStatus } from './auth-status.model'
 import { AuthUser } from './auth-user.model'
 import { objectToUrlEncoded } from '@app/shared/misc/utils'
 import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 interface UserLoginWithUsername extends UserLogin {
   access_token: string
@@ -46,7 +47,8 @@ export class AuthService {
     private http: HttpClient,
     private notificationsService: NotificationsService,
     private restExtractor: RestExtractor,
-    private router: Router
+    private router: Router,
+    private i18n: I18n
   ) {
     this.loginChanged = new Subject<AuthStatus>()
     this.loginChangedSource = this.loginChanged.asObservable()
@@ -74,14 +76,15 @@ export class AuthService {
             let errorMessage = error.message
 
             if (error.status === 403) {
-              errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`
-              errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), ' +
-                'in particular the "webserver" section.'
+              errorMessage = this.i18n('Cannot retrieve OAuth Client credentials: {{ errorText }}.\n', { errorText: error.text })
+              errorMessage += this.i18n(
+                'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'
+              )
             }
 
             // We put a bigger timeout
             // This is an important message
-            this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
+            this.notificationsService.error(this.i18n('Error'), errorMessage, { timeOut: 7000 })
           }
         )
   }
@@ -180,7 +183,7 @@ export class AuthService {
                                              this.router.navigate([ '/login' ])
 
                                              return observableThrowError({
-                                               error: 'You need to reconnect.'
+                                               error: this.i18n('You need to reconnect.')
                                              })
                                            }),
                                            share()
index 01a4e0ac4831bd029dec43d2e24871f26fb48c17..3253de4a0082c9ad44b7db1f08ab763c521c44ca 100644 (file)
@@ -16,7 +16,7 @@
         </div>
 
         <div class="form-group inputs">
-          <span class="action-button action-button-cancel" (click)="cancel()">
+          <span i18n class="action-button action-button-cancel" (click)="cancel()">
             Cancel
           </span>
 
index 147bc9d653adb254aac8a64d5b0ec28fc22517bf..02b38489a9b264083758203b2f561bd0d0671156 100644 (file)
@@ -3,6 +3,7 @@ import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
 import { ModalDirective } from 'ngx-bootstrap/modal'
 
 import { ConfirmService } from './confirm.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-confirm',
@@ -20,7 +21,10 @@ export class ConfirmComponent implements OnInit {
   inputValue = ''
   confirmButtonText = ''
 
-  constructor (private confirmService: ConfirmService) {
+  constructor (
+    private confirmService: ConfirmService,
+    private i18n: I18n
+  ) {
     // Empty
   }
 
@@ -38,7 +42,7 @@ export class ConfirmComponent implements OnInit {
         this.inputLabel = inputLabel
         this.expectedInputValue = expectedInputValue
 
-        this.confirmButtonText = confirmButtonText || 'Confirm'
+        this.confirmButtonText = confirmButtonText || this.i18n('Confirm')
 
         this.showModal()
       }
index c853d2b1b221d6477e77a5dbb1dc4b534b705b6c..a04354db5c75c2dda9357a74d1d6e3a33f03908d 100644 (file)
@@ -1,10 +1,10 @@
 <input
-    type="text" id="search-video" name="search-video" placeholder="Search..."
+    type="text" id="search-video" name="search-video" i18n-placeholder placeholder="Search..."
     [(ngModel)]="searchValue" (keyup.enter)="doSearch()"
 >
 <span (click)="doSearch()" class="icon icon-search"></span>
 
 <a class="upload-button" routerLink="/videos/upload">
   <span class="icon icon-upload"></span>
-  <span class="upload-button-label">Upload</span>
+  <span i18n class="upload-button-label">Upload</span>
 </a>
index b7fd25d27dc32cc039bd0d76c2d8530304c74633..1f6cfdb90a01eaf45f4094e05e4b2503bf5942ab 100644 (file)
@@ -1,5 +1,5 @@
 <div class="margin-content">
-  <div class="title-page title-page-single">
+  <div i18n class="title-page title-page-single">
     Login
   </div>
 
@@ -8,21 +8,21 @@
   <form role="form" (ngSubmit)="login()" [formGroup]="form">
     <div class="form-group">
       <div>
-        <label for="username">User</label>
+        <label i18n for="username">User</label>
         <input
-          type="text" id="username" placeholder="Username or email address" required tabindex="1"
+          type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1"
           formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
         >
-        <a *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account">
+        <a i18n *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account">
           or create an account
         </a>
 
-        <a *ngIf="signupAllowed === false" href="https://joinpeertube.org/en/#getting-started" target="_blank" class="create-an-account">
+        <a i18n *ngIf="signupAllowed === false" href="https://joinpeertube.org/en/#getting-started" target="_blank" class="create-an-account">
           or create an account on another instance
         </a>
 
         <my-help
-          *ngIf="signupAllowed === false" helpType="custom"
+          *ngIf="signupAllowed === false" helpType="custom" i18n-customHtml
           customHtml="User registration is not allowed on this instance, but you can register on many others!"
         ></my-help>
       </div>
     </div>
 
     <div class="form-group">
-      <label for="password">Password</label>
+      <label i18n for="password">Password</label>
       <div>
         <input
-          type="password" name="password" id="password" placeholder="Password" required tabindex="2"
+          type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2"
           formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
         >
-        <div class="forgot-password-button" (click)="openForgotPasswordModal()">I forgot my password</div>
+        <div i18n class="forgot-password-button" (click)="openForgotPasswordModal()">I forgot my password</div>
       </div>
       <div *ngIf="formErrors.password" class="form-error">
         {{ formErrors.password }}
 
       <div class="modal-header">
         <span class="close" aria-hidden="true" (click)="hideForgotPasswordModal()"></span>
-        <h4 class="modal-title">Forgot your password</h4>
+        <h4 i18n class="modal-title">Forgot your password</h4>
       </div>
 
       <div class="modal-body">
         <div class="form-group">
-          <label for="forgot-password-email">Email</label>
+          <label i18n for="forgot-password-email">Email</label>
           <input
-            type="email" id="forgot-password-email" placeholder="Email address" required
+            type="email" id="forgot-password-email" i18n-placeholder placeholder="Email address" required
             [(ngModel)]="forgotPasswordEmail" #forgotPasswordEmailInput
           >
         </div>
 
         <div class="form-group inputs">
-          <span class="action-button action-button-cancel" (click)="hideForgotPasswordModal()">
+          <span i18n class="action-button action-button-cancel" (click)="hideForgotPasswordModal()">
             Cancel
           </span>
 
           <input
-            type="submit" value="Send me an email to reset my password" class="action-button-submit"
+            type="submit" i18n-value value="Send me an email to reset my password" class="action-button-submit"
             (click)="askResetPassword()" [disabled]="!forgotPasswordEmailInput.validity.valid"
           >
         </div>
index 2514faf94f6662582b3fbcca1388a0cae8f8a8b7..a14cb2eb7243e81fc9ba8ba03dc50cd38c29efc6 100644 (file)
@@ -7,6 +7,7 @@ import { NotificationsService } from 'angular2-notifications'
 import { ModalDirective } from 'ngx-bootstrap/modal'
 import { AuthService } from '../core'
 import { FormReactive } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-login',
@@ -35,12 +36,15 @@ export class LoginComponent extends FormReactive implements OnInit {
   }
   forgotPasswordEmail = ''
 
-  constructor (private authService: AuthService,
-               private userService: UserService,
-               private serverService: ServerService,
-               private redirectService: RedirectService,
-               private notificationsService: NotificationsService,
-               private formBuilder: FormBuilder) {
+  constructor (
+    private authService: AuthService,
+    private userService: UserService,
+    private serverService: ServerService,
+    private redirectService: RedirectService,
+    private notificationsService: NotificationsService,
+    private formBuilder: FormBuilder,
+    private i18n: I18n
+  ) {
     super()
   }
 
@@ -78,12 +82,15 @@ export class LoginComponent extends FormReactive implements OnInit {
     this.userService.askResetPassword(this.forgotPasswordEmail)
       .subscribe(
         res => {
-          const message = `An email with the reset password instructions will be sent to ${this.forgotPasswordEmail}.`
-          this.notificationsService.success('Success', message)
+          const message = this.i18n(
+            'An email with the reset password instructions will be sent to {{ email }}.',
+            { email: this.forgotPasswordEmail }
+          )
+          this.notificationsService.success(this.i18n('Success'), message)
           this.hideForgotPasswordModal()
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
index 1a95477b7672ca30cf5ce900965c02c2d7f8de37..1677294054f7728cb8001a19909236a66471172c 100644 (file)
            My public profile
           </a>
 
-          <a routerLink="/my-account/settings" class="dropdown-item" title="My settings">
+          <a i18n routerLink="/my-account/settings" class="dropdown-item" title="My settings">
             My settings
           </a>
 
-          <a (click)="logout($event)" class="dropdown-item" title="Log out" href="#">
+          <a i18n (click)="logout($event)" class="dropdown-item" title="Log out" href="#">
             Log out
           </a>
         </li>
   </div>
 
   <div *ngIf="!isLoggedIn" class="button-block">
-    <a routerLink="/login" class="login-button">Login</a>
-    <a *ngIf="isRegistrationAllowed()" routerLink="/signup" class="create-account-button">Create an account</a>
+    <a i18n routerLink="/login" class="login-button">Login</a>
+    <a i18n *ngIf="isRegistrationAllowed()" routerLink="/signup" class="create-account-button">Create an account</a>
   </div>
 
   <div class="panel-block">
-    <div class="block-title">Videos</div>
+    <div i18n class="block-title">Videos</div>
 
     <a routerLink="/videos/trending" routerLinkActive="active">
       <span class="icon icon-videos-trending"></span>
-      Trending
+      <ng-container i18n>Trending</ng-container>
     </a>
 
     <a routerLink="/videos/recently-added" routerLinkActive="active">
       <span class="icon icon-videos-recently-added"></span>
-      Recently added
+      <ng-container i18n>Recently added</ng-container>
     </a>
 
     <a routerLink="/videos/local" routerLinkActive="active">
       <span class="icon icon-videos-local"></span>
-      Local
+      <ng-container i18n>Local</ng-container>
     </a>
   </div>
 
 
     <a *ngIf="userHasAdminAccess" [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active">
       <span class="icon icon-administration"></span>
-      Administration
+      <ng-container i18n>Administration</ng-container>
     </a>
 
     <a routerLink="/about" routerLinkActive="active">
       <span class="icon icon-about"></span>
-      About
+      <ng-container i18n>About</ng-container>
     </a>
   </div>
 </menu>
index 69216e2150c37dfcea3e57490d05f6bb281581ce..c0aea89b33d9bc2d408858ce4ff857eb04d4b324 100644 (file)
@@ -1,7 +1,7 @@
 import { Component, OnInit } from '@angular/core'
 import { Router } from '@angular/router'
 import { UserRight } from '../../../../shared/models/users/user-right.enum'
-import { AuthService, AuthStatus, ServerService } from '../core'
+import { AuthService, AuthStatus, RedirectService, ServerService } from '../core'
 import { User } from '../shared/users/user.model'
 
 @Component({
@@ -24,7 +24,7 @@ export class MenuComponent implements OnInit {
   constructor (
     private authService: AuthService,
     private serverService: ServerService,
-    private router: Router
+    private redirectService: RedirectService
   ) {}
 
   ngOnInit () {
@@ -87,7 +87,7 @@ export class MenuComponent implements OnInit {
 
     this.authService.logout()
     // Redirect to home page
-    this.router.navigate(['/videos/list'])
+    this.redirectService.redirectToHomepage()
   }
 
   private computeIsUserHasAdminAccess () {
index 9cf623c64776ac943aac4715bb35939ee9f32c31..20e62d0b7ba6ba89a27c85a1b09e322fec3347c3 100644 (file)
@@ -1,13 +1,13 @@
 <div class="margin-content">
-  <div class="title-page title-page-single">
+  <div i18n class="title-page title-page-single">
     Reset my password
   </div>
 
   <form role="form" (ngSubmit)="resetPassword()" [formGroup]="form">
     <div class="form-group">
-      <label for="password">Password</label>
+      <label i18n for="password">Password</label>
       <input
-        type="password" name="password" id="password" placeholder="Password" required
+        type="password" name="password" id="password" i18n-placeholder placeholder="Password" required
         formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
       >
       <div *ngIf="formErrors.password" class="form-error">
@@ -16,9 +16,9 @@
     </div>
 
     <div class="form-group">
-      <label for="password-confirm">Confirm password</label>
+      <label i18n for="password-confirm">Confirm password</label>
       <input
-        type="password" name="password-confirm" id="password-confirm" placeholder="Confirmed password" required
+        type="password" name="password-confirm" id="password-confirm" i18n-placeholder placeholder="Confirmed password" required
         formControlName="password-confirm" [ngClass]="{ 'input-error': formErrors['password-confirm'] }"
       >
       <div *ngIf="formErrors['password-confirm']" class="form-error">
@@ -26,6 +26,6 @@
       </div>
     </div>
 
-    <input type="submit" value="Reset my password" [disabled]="!form.valid && isConfirmedPasswordValid()">
+    <input type="submit" i18n-value value="Reset my password" [disabled]="!form.valid && isConfirmedPasswordValid()">
   </form>
 </div>
index 4083747797f7f8144a8db7588869331f43d170b9..c8bd368c19df09e2928f9fd5507cbd5f91915ed5 100644 (file)
@@ -5,6 +5,7 @@ import { USER_PASSWORD, UserService } from '@app/shared'
 import { NotificationsService } from 'angular2-notifications'
 import { AuthService } from '../core'
 import { FormReactive } from '../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-login',
@@ -34,7 +35,8 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
     private notificationsService: NotificationsService,
     private formBuilder: FormBuilder,
     private router: Router,
-    private route: ActivatedRoute
+    private route: ActivatedRoute,
+    private i18n: I18n
   ) {
     super()
   }
@@ -55,7 +57,7 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
     this.verificationString = this.route.snapshot.queryParams['verificationString']
 
     if (!this.userId || !this.verificationString) {
-      this.notificationsService.error('Error', 'Unable to find user id or verification string.')
+      this.notificationsService.error(this.i18n('Error'), this.i18n('Unable to find user id or verification string.'))
       this.router.navigate([ '/' ])
     }
   }
@@ -64,7 +66,7 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
     this.userService.resetPassword(this.userId, this.verificationString, this.form.value.password)
       .subscribe(
         () => {
-          this.notificationsService.success('Success', 'Your password has been successfully reset!')
+          this.notificationsService.success(this.i18n('Success'), this.i18n('Your password has been successfully reset!'))
           this.router.navigate([ '/login' ])
         },
 
index 46a97b163d42f3270e459e8347a343d887101ceb..6effda5b8520601d683304714460b33c639af388 100644 (file)
@@ -6,7 +6,7 @@
   </textarea>
 
   <tabset *ngIf="arePreviewsDisplayed()" class="previews">
-    <tab *ngIf="truncate !== undefined" heading="Truncated preview" [innerHTML]="truncatedPreviewHTML"></tab>
-    <tab heading="Complete preview" [innerHTML]="previewHTML"></tab>
+    <tab *ngIf="truncate !== undefined" i18n-heading heading="Truncated preview" [innerHTML]="truncatedPreviewHTML"></tab>
+    <tab i18n-heading heading="Complete preview" [innerHTML]="previewHTML"></tab>
   </tabset>
 </div>
index dcc85f3cdbbe17ee6b1b456849dcb633a57d4d96..8b932cd15a437f0b8f0f2b0533666ce67ff3fce3 100644 (file)
@@ -3,7 +3,7 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'
 import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
 import { isInSmallView } from '@app/shared/misc/utils'
 import { MarkdownService } from '@app/videos/shared'
-import { Subject } from 'rxjs'
+import { Subject } from 'rxjs/Subject'
 import truncate from 'lodash-es/truncate'
 
 @Component({
index 550dd656eaf5d8ae348f38e89dd35dfa9bbe1fed..c038a5c0edae4dd81ead969cd6c361d534575605 100644 (file)
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'
 import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot } from '@angular/router'
 import { Observable } from 'rxjs'
 import { ConfirmService } from '../../core/index'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 export interface CanComponentDeactivate {
   canDeactivate: () => { text?: string, canDeactivate: Observable<boolean> | boolean }
@@ -9,7 +10,10 @@ export interface CanComponentDeactivate {
 
 @Injectable()
 export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
-  constructor (private confirmService: ConfirmService) { }
+  constructor (
+    private confirmService: ConfirmService,
+    private i18n: I18n
+  ) { }
 
   canDeactivate (component: CanComponentDeactivate,
     currentRoute: ActivatedRouteSnapshot,
@@ -17,11 +21,11 @@ export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate>
     nextState: RouterStateSnapshot
   ) {
     const result = component.canDeactivate()
-    const text = result.text || 'All unsaved data will be lost, are you sure you want to leave this page?'
+    const text = result.text || this.i18n('All unsaved data will be lost, are you sure you want to leave this page?')
 
     return result.canDeactivate || this.confirmService.confirm(
       text,
-      'Warning'
+      this.i18n('Warning')
     )
   }
 
index 632d6bba20b7f44b810348438c62d3bdf9fc65a0..78fbc326e6a28140926d09ddb70b29681d1fcb94 100644 (file)
@@ -1,4 +1,4 @@
 <a class="action-button action-button-edit" [routerLink]="routerLink" title="Edit">
   <span class="icon icon-edit"></span>
-  <span class="button-label">Edit</span>
+  <span i18n class="button-label">Edit</span>
 </a>
index fac02af0bd6b59e3aa23c1e10d5ccc766f2b428b..3a64a4077c349e3c089afa8a57179b433c35229a 100644 (file)
@@ -1,36 +1,39 @@
 import { Pipe, PipeTransform } from '@angular/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 // Thanks: https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site
 @Pipe({ name: 'myFromNow' })
 export class FromNowPipe implements PipeTransform {
 
+  constructor (private i18n: I18n) { }
+
   transform (value: number) {
     const seconds = Math.floor((Date.now() - value) / 1000)
 
     let interval = Math.floor(seconds / 31536000)
     if (interval > 1) {
-      return interval + ' years ago'
+      return this.i18n('{{ interval }} years ago', { interval })
     }
 
     interval = Math.floor(seconds / 2592000)
-    if (interval > 1) return interval + ' months ago'
-    if (interval === 1) return interval + ' month ago'
+    if (interval > 1) return this.i18n('{{ interval }} months ago', { interval })
+    if (interval === 1) return this.i18n('{{ interval }} month ago', { interval })
 
     interval = Math.floor(seconds / 604800)
-    if (interval > 1) return interval + ' weeks ago'
-    if (interval === 1) return interval + ' week ago'
+    if (interval > 1) return this.i18n('{{ interval }} weeks ago', { interval })
+    if (interval === 1) return this.i18n('{{ interval }} week ago', { interval })
 
     interval = Math.floor(seconds / 86400)
-    if (interval > 1) return interval + ' days ago'
-    if (interval === 1) return interval + ' day ago'
+    if (interval > 1) return this.i18n('{{ interval }} days ago', { interval })
+    if (interval === 1) return this.i18n('{{ interval }} day ago', { interval })
 
     interval = Math.floor(seconds / 3600)
-    if (interval > 1) return interval + ' hours ago'
-    if (interval === 1) return interval + ' hour ago'
+    if (interval > 1) return this.i18n('{{ interval }} hours ago', { interval })
+    if (interval === 1) return this.i18n('{{ interval }} hour ago', { interval })
 
     interval = Math.floor(seconds / 60)
-    if (interval >= 1) return interval + ' min ago'
+    if (interval >= 1) return this.i18n('{{ interval }} min ago', { interval })
 
-    return Math.floor(seconds) + ' sec ago'
+    return this.i18n('{{ interval }} sec ago', { interval: Math.floor(seconds) })
   }
 }
index 3da5701a0ee686c88e52bec5bbe25a9cdb0e595e..f2b6eca330c0d46113e1165f11cd10ce626dd87d 100644 (file)
@@ -15,6 +15,7 @@
 <span
   class="help-tooltip-button"
   title="Get help"
+  i18n-title
   [popover]="tooltipTemplate"
   [placement]="tooltipPlacement"
   [outsideClick]="true"
index 39e601e201f2900d8ea1e39cda817867b1a872b9..468ac3e32e5cc753eda7772ceba3253ffcb04798 100644 (file)
@@ -3,11 +3,15 @@ import { Injectable } from '@angular/core'
 import { dateToHuman } from '@app/shared/misc/utils'
 import { ResultList } from '../../../../../shared'
 import { Router } from '@angular/router'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Injectable()
 export class RestExtractor {
 
-  constructor (private router: Router) {
+  constructor (
+    private router: Router,
+    private i18n: I18n
+  ) {
     // empty
   }
 
@@ -60,17 +64,19 @@ export class RestExtractor {
       } else if (err.error && err.error.error) {
         errorMessage = err.error.error
       } else if (err.status === 413) {
-        errorMessage = 'Request is too large for the server. Please contact you administrator if you want to increase the limit size.'
+        errorMessage = this.i18n(
+          'Request is too large for the server. Please contact you administrator if you want to increase the limit size.'
+        )
       } else if (err.status === 429) {
         const secondsLeft = err.headers.get('retry-after')
         if (secondsLeft) {
           const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60)
-          errorMessage = 'Too many attempts, please try again after ' + minutesLeft + ' minutes.'
+          errorMessage = this.i18n('Too many attempts, please try again after {{ minutesLeft }} minutes.', { minutesLeft })
         } else {
-          errorMessage = 'Too many attempts, please try again later.'
+          errorMessage = this.i18n('Too many attempts, please try again later.')
         }
       } else if (err.status === 500) {
-        errorMessage = 'Server error. Please retry later.'
+        errorMessage = this.i18n('Server error. Please retry later.')
       }
 
       errorMessage = errorMessage ? errorMessage : 'Unknown error.'
index 690529dcf5a371ff14ca9ef90bc42b8d2bc565b6..e8ded6ab8c63d53233952df8fba4adc853d815c2 100644 (file)
@@ -4,7 +4,7 @@
   </div>
   <my-video-feed [syndicationItems]="syndicationItems"></my-video-feed>
 
-  <div *ngIf="pagination.totalItems === 0">No results.</div>
+  <div i18n *ngIf="pagination.totalItems === 0">No results.</div>
   <div
     myInfiniteScroller
     [pageHeight]="pageHeight"
index 100cbff8d4905715e04505e908920e7ad8b2ec52..1c84573da892d1a74179db3da3b6ab8792a25136 100644 (file)
@@ -10,6 +10,7 @@ import { AuthService } from '../../core/auth'
 import { ComponentPagination } from '../rest/component-pagination.model'
 import { VideoSortField } from './sort-field.type'
 import { Video } from './video.model'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 export abstract class AbstractVideoList implements OnInit, OnDestroy {
   private static LINES_PER_PAGE = 4
@@ -40,6 +41,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
   protected abstract authService: AuthService
   protected abstract router: Router
   protected abstract route: ActivatedRoute
+  protected abstract i18n: I18n
   protected abstract location: Location
   protected abstract currentRoute: string
   abstract titlePage: string
@@ -124,7 +126,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
       },
       error => {
         this.loadingPage[page] = false
-        this.notificationsService.error('Error', error.message)
+        this.notificationsService.error(this.i18n('Error'), error.message)
       }
     )
   }
index 09ce0ef7f18ba96c3a4d2d61fe68aea8f7dba01f..3010e5ccc2864047c1122d56e3c1f2bd4788ca44 100644 (file)
@@ -9,7 +9,7 @@
       {{ video.name }}
     </a>
 
-    <span class="video-miniature-created-at-views">{{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
+    <span i18n class="video-miniature-created-at-views">{{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
     <a class="video-miniature-account" [routerLink]="[ '/accounts', video.by ]">{{ video.by }}</a>
   </div>
 </div>
index 4604d10e250f4b6490facd14a2dce13c3880a043..971f352ba3eee20ce27197f3f507002b2e85206a 100644 (file)
@@ -1,6 +1,6 @@
 <a
   [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name"
-class="video-thumbnail"
+  class="video-thumbnail"
 >
 <img [attr.src]="getImageUrl()" [ngClass]="{ 'blur-filter': nsfw }" />
 
index 5f48786e51ba3d4075ed995b4480f38ede087714..2fe9a42818013e6fd03c32d81bccd7560eb0b72c 100644 (file)
@@ -1,11 +1,11 @@
 <div class="margin-content">
 
-  <div class="title-page title-page-single">
+  <div i18n class="title-page title-page-single">
     Create an account
   </div>
 
   <div class="initial-user-quota">
-    <span class="initial-user-quota-label">Initial video quota:</span>
+    <span i18n class="initial-user-quota-label">Initial video quota:</span>
 
     <span *ngIf="initialUserVideoQuota !== -1">
       {{ initialUserVideoQuota | bytes: 0 }}
       <my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
     </span>
 
-    <ng-template [ngIf]="initialUserVideoQuota === -1">
+    <ng-container i18n *ngIf="initialUserVideoQuota === -1">
       Unlimited
-    </ng-template>
+    </ng-container>
   </div>
 
   <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
 
   <form role="form" (ngSubmit)="signup()" [formGroup]="form">
     <div class="form-group">
-      <label for="username">Username</label>
+      <label for="username" i18n>Username</label>
       <input
-        type="text" id="username" placeholder="Username"
+        type="text" id="username" i18n-placeholder placeholder="Username"
         formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
       >
       <div *ngIf="formErrors.username" class="form-error">
@@ -33,9 +33,9 @@
     </div>
 
     <div class="form-group">
-      <label for="email">Email</label>
+      <label for="email" i18n>Email</label>
       <input
-        type="text" id="email" placeholder="Email"
+        type="text" id="email" i18n-placeholder placeholder="Email"
         formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
       >
       <div *ngIf="formErrors.email" class="form-error">
@@ -44,9 +44,9 @@
     </div>
 
     <div class="form-group">
-      <label for="password">Password</label>
+      <label for="password" i18n>Password</label>
       <input
-        type="password" id="password" placeholder="Password"
+        type="password" id="password" i18n-placeholder placeholder="Password"
         formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
       >
       <div *ngIf="formErrors.password" class="form-error">
@@ -54,7 +54,7 @@
       </div>
     </div>
 
-    <input type="submit" value="Signup" [disabled]="!form.valid">
+    <input type="submit" i18n-value value="Signup" [disabled]="!form.valid">
   </form>
 
 </div>
index 1f3e2e1461b352c667e75058f900f6f0b5151929..4a49ead50d6aa9bec71ed4a018d779a9f9a35d53 100644 (file)
@@ -6,6 +6,8 @@ import { ServerService } from '@app/core/server'
 import { NotificationsService } from 'angular2-notifications'
 import { UserCreate } from '../../../../shared'
 import { FormReactive, USER_EMAIL, USER_PASSWORD, USER_USERNAME, UserService } from '../shared'
+import { RedirectService } from '@app/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-signup',
@@ -45,7 +47,9 @@ export class SignupComponent extends FormReactive implements OnInit {
     private router: Router,
     private notificationsService: NotificationsService,
     private userService: UserService,
-    private serverService: ServerService
+    private redirectService: RedirectService,
+    private serverService: ServerService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -78,8 +82,11 @@ export class SignupComponent extends FormReactive implements OnInit {
 
     this.userService.signup(userCreate).subscribe(
       () => {
-        this.notificationsService.success('Success', `Registration for ${userCreate.username} complete.`)
-        this.router.navigate([ '/videos/list' ])
+        this.notificationsService.success(
+          this.i18n('Success'),
+          this.i18n('Registration for {{ username }} complete.', { username: userCreate.username})
+        )
+        this.redirectService.redirectToHomepage()
       },
 
       err => this.error = err.message
@@ -99,9 +106,9 @@ export class SignupComponent extends FormReactive implements OnInit {
     const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
 
     const lines = [
-      SignupComponent.getApproximateTime(fullHdSeconds) + ' of full HD videos',
-      SignupComponent.getApproximateTime(hdSeconds) + ' of HD videos',
-      SignupComponent.getApproximateTime(normalSeconds) + ' of average quality videos'
+      this.i18n('{{ seconds }} of full HD videos', { seconds: SignupComponent.getApproximateTime(fullHdSeconds) }),
+      this.i18n('{{ seconds }} of HD videos', { seconds: SignupComponent.getApproximateTime(hdSeconds) }),
+      this.i18n('{{ seconds }} of average quality videos', { seconds: SignupComponent.getApproximateTime(normalSeconds) })
     ]
 
     this.quotaHelpIndication = lines.join('<br />')
index 7e1be446704032c481cdcef6f0c28e8b35f1bd31..bd9f6936254c046f663fd47428f0072271376323 100644 (file)
@@ -4,7 +4,7 @@
     <tab heading="Basic info">
       <div class="col-md-8">
         <div class="form-group">
-          <label for="name">Title</label>
+          <label i18n for="name">Title</label>
           <input type="text" id="name" formControlName="name" />
           <div *ngIf="formErrors.name" class="form-error">
             {{ formErrors.name }}
@@ -12,7 +12,7 @@
         </div>
 
         <div class="form-group">
-          <label class="label-tags">Tags</label> <span>(press Enter to add)</span>
+          <label i18n class="label-tags">Tags</label> <span i18n>(press Enter to add)</span>
           <tag-input
             [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
             formControlName="tags" maxItems="5" modelAsStrings="true"
@@ -20,8 +20,8 @@
         </div>
 
         <div class="form-group">
-          <label for="description">Description</label>
-          <my-help helpType="markdownText" preHtml="Video descriptions are truncated by default and require manual action to expand them."></my-help>
+          <label i18n for="description">Description</label>
+          <my-help helpType="markdownText" i18n-preHtml preHtml="Video descriptions are truncated by default and require manual action to expand them."></my-help>
           <my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
 
           <div *ngIf="formErrors.description" class="form-error">
@@ -32,7 +32,7 @@
 
       <div class="col-md-4">
         <div class="form-group">
-          <label>Channel</label>
+          <label i18n>Channel</label>
           <div class="peertube-select-container">
             <select formControlName="channelId">
               <option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
@@ -41,7 +41,7 @@
         </div>
 
         <div class="form-group">
-          <label for="category">Category</label>
+          <label i18n for="category">Category</label>
           <div class="peertube-select-container">
             <select id="category" formControlName="category">
               <option></option>
@@ -55,7 +55,7 @@
         </div>
 
         <div class="form-group">
-          <label for="licence">Licence</label>
+          <label i18n for="licence">Licence</label>
           <div class="peertube-select-container">
             <select id="licence" formControlName="licence">
               <option></option>
@@ -69,7 +69,7 @@
         </div>
 
         <div class="form-group">
-          <label for="language">Language</label>
+          <label i18n for="language">Language</label>
           <div class="peertube-select-container">
             <select id="language" formControlName="language">
               <option></option>
@@ -83,7 +83,7 @@
         </div>
 
         <div class="form-group">
-          <label for="privacy">Privacy</label>
+          <label i18n for="privacy">Privacy</label>
           <div class="peertube-select-container">
             <select id="privacy" formControlName="privacy">
               <option></option>
         <div class="form-group form-group-checkbox">
           <input type="checkbox" id="nsfw" formControlName="nsfw" />
           <label for="nsfw"></label>
-          <label for="nsfw">This video contains mature or explicit content</label>
-          <my-help tooltipPlacement="top" helpType="custom" customHtml="Some instances do not list NSFW videos by default."></my-help>
+          <label i18n for="nsfw">This video contains mature or explicit content</label>
+          <my-help tooltipPlacement="top" helpType="custom" i18n-customHtml customHtml="Some instances do not list NSFW videos by default."></my-help>
         </div>
 
         <div class="form-group form-group-checkbox">
           <input type="checkbox" id="commentsEnabled" formControlName="commentsEnabled" />
           <label for="commentsEnabled"></label>
-          <label for="commentsEnabled">Enable video comments</label>
+          <label i18n for="commentsEnabled">Enable video comments</label>
         </div>
 
       </div>
       <div class="col-md-12 advanced-settings">
         <div class="form-group">
           <my-video-image
-            inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
+            i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
             previewWidth="200px" previewHeight="110px"
           ></my-video-image>
         </div>
 
         <div class="form-group">
           <my-video-image
-            inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile"
+            i18n-inputLabel inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile"
             previewWidth="360px" previewHeight="200px"
           ></my-video-image>
         </div>
 
         <div class="form-group">
-          <label for="support">Support</label>
-          <my-help helpType="markdownEnhanced" preHtml="Short text to tell people how they can support you (membership platform...)."></my-help>
+          <label i18n for="support">Support</label>
+          <my-help helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support you (membership platform...)."></my-help>
           <my-markdown-textarea
-              id="support" formControlName="support" textareaWidth="500px" [previewColumn]="true" markdownType="enhanced"
-              [classes]="{ 'input-error': formErrors['support'] }"
+            id="support" formControlName="support" textareaWidth="500px" [previewColumn]="true" markdownType="enhanced"
+            [classes]="{ 'input-error': formErrors['support'] }"
           ></my-markdown-textarea>
           <div *ngIf="formErrors.support" class="form-error">
             {{ formErrors.support }}
index 5d0624f8c2ef1e9b4c7560b81faf697474e35600..e319d7ee79f353ef2f38bed70ee3ba92ea366d8d 100644 (file)
@@ -8,7 +8,7 @@
         (change)="fileChange($event)"
       />
     </div>
-    <div class="image-constraints">(extensions: {{ videoImageExtensions }}, max size: {{ maxVideoImageSize | bytes }})</div>
+    <div i18n class="image-constraints">(extensions: {{ videoImageExtensions }}, max size: {{ maxVideoImageSize | bytes }})</div>
   </div>
 
   <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" />
index 440556562b72bf39a53f981c5381a9bf628145bc..f00cfe0162026008ded6f0af53ed2e6936e3f7df 100644 (file)
@@ -1,7 +1,7 @@
 <div class="margin-content">
   <div class="title-page title-page-single">
-    <ng-template [ngIf]="!videoFileName">Upload your video</ng-template>
-    <ng-template [ngIf]="videoFileName">Upload {{ videoFileName }}</ng-template>
+    <ng-container *ngIf="!videoFileName" i18n>Upload your video</ng-container>
+    <ng-container *ngIf="videoFileName" i18n>Upload {{ videoFileName }}</ng-container>
   </div>
 
   <div *ngIf="!isUploadingVideo" class="upload-video-container">
@@ -9,12 +9,12 @@
       <div class="icon icon-upload"></div>
 
       <div class="button-file">
-        <span>Select the file to upload</span>
+        <span i18n>Select the file to upload</span>
         <input #videofileInput type="file" name="videofile" id="videofile" [accept]="videoExtensions" (change)="fileChange()" />
       </div>
 
       <div class="form-group form-group-channel">
-        <label for="first-step-channel">Channel</label>
+        <label i18n for="first-step-channel">Channel</label>
         <div class="peertube-select-container">
           <select id="first-step-channel" [(ngModel)]="firstStepChannelId">
             <option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
@@ -23,7 +23,7 @@
       </div>
 
       <div class="form-group">
-        <label for="first-step-privacy">Privacy</label>
+        <label i18n for="first-step-privacy">Privacy</label>
         <div class="peertube-select-container">
           <select id="first-step-privacy" [(ngModel)]="firstStepPrivacyId">
             <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
     ></my-video-edit>
 
     <div class="submit-container">
-      <div *ngIf="videoUploaded === false" class="message-submit">Publish will be available when upload is finished</div>
+      <div i18n *ngIf="videoUploaded === false" class="message-submit">Publish will be available when upload is finished</div>
 
       <div class="submit-button"
          (click)="updateSecondStep()"
          [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true || videoUploaded !== true }"
       >
         <span class="icon icon-validate"></span>
-        <input type="button" value="Publish" />
+        <input type="button" i18n-value value="Publish" />
       </div>
     </div>
   </form>
index 997f033b75faa3b9a38078008fc8a629f9a746fc..a615fd92c3ecdf6ad0853be472c77bbd08cc2c4b 100644 (file)
@@ -15,6 +15,7 @@ import { ValidatorMessage } from '../../shared/forms/form-validators/validator-m
 import { populateAsyncUserVideoChannels } from '../../shared/misc/utils'
 import { VideoEdit } from '../../shared/video/video-edit.model'
 import { VideoService } from '../../shared/video/video.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-videos-add',
@@ -56,7 +57,8 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
     private userService: UserService,
     private serverService: ServerService,
     private videoService: VideoService,
-    private loadingBar: LoadingBarService
+    private loadingBar: LoadingBarService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -99,10 +101,11 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
     let text = ''
 
     if (this.videoUploaded === true) {
-      text = 'Your video was uploaded in your account and is private.' +
-        ' But associated data (tags, description...) will be lost, are you sure you want to leave this page?'
+      // FIXME: cannot concatenate strings inside i18n service :/
+      text = this.i18n('Your video was uploaded in your account and is private.') +
+        this.i18n('But associated data (tags, description...) will be lost, are you sure you want to leave this page?')
     } else {
-      text = 'Your video is not uploaded yet, are you sure you want to leave this page?'
+      text = this.i18n('Your video is not uploaded yet, are you sure you want to leave this page?')
     }
 
     return {
@@ -127,7 +130,7 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
       this.isUploadingVideo = false
       this.videoUploadPercents = 0
       this.videoUploadObservable = null
-      this.notificationsService.info('Info', 'Upload cancelled')
+      this.notificationsService.info(this.i18n('Info'), this.i18n('Upload cancelled'))
     }
   }
 
@@ -137,7 +140,7 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
 
     // Cannot upload videos > 4GB for now
     if (videofile.size > 4 * 1024 * 1024 * 1024) {
-      this.notificationsService.error('Error', 'We are sorry but PeerTube cannot handle videos > 4GB')
+      this.notificationsService.error(this.i18n('Error'), this.i18n('We are sorry but PeerTube cannot handle videos > 4GB'))
       return
     }
 
@@ -145,11 +148,15 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
     if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
       const bytePipes = new BytesPipe()
 
-      const msg = 'Your video quota is exceeded with this video ' +
-        `(video size: ${bytePipes.transform(videofile.size, 0)}, ` +
-        `used: ${bytePipes.transform(this.userVideoQuotaUsed, 0)}, ` +
-        `quota: ${bytePipes.transform(videoQuota, 0)})`
-      this.notificationsService.error('Error', msg)
+      const msg = this.i18n(
+        'Your video quota is exceeded with this video (video size: {{ videoSize }}, used: {{ videoQuotaUsed }}, quota: {{ videoQuota }})',
+        {
+          videoSize: bytePipes.transform(videofile.size, 0),
+          videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0),
+          videoQuota: bytePipes.transform(videoQuota, 0)
+        }
+      )
+      this.notificationsService.error(this.i18n('Error'), msg)
       return
     }
 
@@ -192,8 +199,6 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
         if (event.type === HttpEventType.UploadProgress) {
           this.videoUploadPercents = Math.round(100 * event.loaded / event.total)
         } else if (event instanceof HttpResponse) {
-          console.log('Video uploaded.')
-
           this.videoUploaded = true
 
           this.videoUploadedIds = event.body.video
@@ -207,7 +212,7 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
         this.isUploadingVideo = false
         this.videoUploadPercents = 0
         this.videoUploadObservable = null
-        this.notificationsService.error('Error', err.message)
+        this.notificationsService.error(this.i18n('Error'), err.message)
       }
     )
   }
@@ -231,13 +236,13 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
           this.isUploadingVideo = false
           this.loadingBar.complete()
 
-          this.notificationsService.success('Success', 'Video published.')
+          this.notificationsService.success(this.i18n('Success'), this.i18n('Video published.'))
           this.router.navigate([ '/videos/watch', video.uuid ])
         },
 
         err => {
           this.isUpdatingVideo = false
-          this.notificationsService.error('Error', err.message)
+          this.notificationsService.error(this.i18n('Error'), err.message)
           console.error(err)
         }
       )
index a1b4707be71b6325ec8eef2a6b137aa8e4b32e01..73b2bc08f72a15c820f04a557ccd45d3ca79b390 100644 (file)
@@ -1,5 +1,5 @@
 <div class="margin-content">
-  <div class="title-page title-page-single">
+  <div i18n class="title-page title-page-single">
     Update {{ video?.name }}
   </div>
 
@@ -13,7 +13,7 @@
     <div class="submit-container">
       <div class="submit-button" (click)="update()" [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }">
         <span class="icon icon-validate"></span>
-        <input type="button" value="Update" />
+        <input type="button" i18n-value value="Update" />
       </div>
     </div>
   </form>
index 310285f923caac1723e62c95cfd73cee1180c068..e37dd526fc794f3186b80786ba0cfe30185c3304 100644 (file)
@@ -12,6 +12,7 @@ import { ValidatorMessage } from '../../shared/forms/form-validators/validator-m
 import { VideoEdit } from '../../shared/video/video-edit.model'
 import { VideoService } from '../../shared/video/video.service'
 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-videos-update',
@@ -37,7 +38,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
     private videoService: VideoService,
     private authService: AuthService,
     private loadingBar: LoadingBarService,
-    private videoChannelService: VideoChannelService
+    private videoChannelService: VideoChannelService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -91,7 +93,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
 
           err => {
             console.error(err)
-            this.notificationsService.error('Error', err.message)
+            this.notificationsService.error(this.i18n('Error'), err.message)
           }
         )
   }
@@ -116,13 +118,13 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
                        () => {
                          this.isUpdatingVideo = false
                          this.loadingBar.complete()
-                         this.notificationsService.success('Success', 'Video updated.')
+                         this.notificationsService.success(this.i18n('Success'), this.i18n('Video updated.'))
                          this.router.navigate([ '/videos/watch', this.video.uuid ])
                        },
 
                        err => {
                          this.isUpdatingVideo = false
-                         this.notificationsService.error('Error', err.message)
+                         this.notificationsService.error(this.i18n('Error'), err.message)
                          console.error(err)
                        }
                       )
index 54d7286db5f5792b0711fec807dc9ac5f7d5dfce..eaf068cfa4d410d150e8d421d6abd6d2889b00d0 100644 (file)
@@ -3,7 +3,7 @@
     <img [src]="user.accountAvatarUrl" alt="Avatar" />
 
     <div class="form-group">
-      <textarea placeholder="Add comment..." formControlName="text" [ngClass]="{ 'input-error': formErrors['text'] }"
+      <textarea i18n-placeholder placeholder="Add comment..." formControlName="text" [ngClass]="{ 'input-error': formErrors['text'] }"
                 (keyup.control.enter)="onValidKey()" (keyup.meta.enter)="onValidKey()" #textarea>
 
       </textarea>
@@ -14,7 +14,7 @@
   </div>
 
   <div class="submit-comment">
-    <button *ngIf="isAddButtonDisplayed()" [ngClass]="{ disabled: !form.valid }">
+    <button *ngIf="isAddButtonDisplayed()" [ngClass]="{ disabled: !form.valid }" i18n>
       Post comment
     </button>
   </div>
index b1f4464751113142a6d6bd75f2a00cc5cf69674f..2ee5f5ef1e1b1c7d522452c13d60cdea47aa8220 100644 (file)
@@ -9,6 +9,7 @@ import { User } from '../../../shared/users'
 import { Video } from '../../../shared/video/video.model'
 import { VideoComment } from './video-comment.model'
 import { VideoCommentService } from './video-comment.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-comment-add',
@@ -37,7 +38,8 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
   constructor (
     private formBuilder: FormBuilder,
     private notificationsService: NotificationsService,
-    private videoCommentService: VideoCommentService
+    private videoCommentService: VideoCommentService,
+    private i18n: I18n
   ) {
     super()
   }
@@ -92,7 +94,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
         this.form.reset()
       },
 
-      err => this.notificationsService.error('Error', err.text)
+      err => this.notificationsService.error(this.i18n('Error'), err.text)
     )
   }
 
index 06808ef808b15297173218a5821a62542bf282fb..60b803206220489185679d5baf40006137ecb620 100644 (file)
@@ -2,7 +2,7 @@
   <img [src]="comment.accountAvatarUrl" alt="Avatar" />
 
   <div class="comment">
-    <div *ngIf="highlightedComment === true" class="highlighted-comment">Highlighted comment</div>
+    <div *ngIf="highlightedComment === true" class="highlighted-comment" i18n>Highlighted comment</div>
 
     <div class="comment-account-date">
       <a [href]="comment.account.url"  target="_blank" rel="noopener noreferrer" class="comment-account">{{ comment.by }}</a>
@@ -11,8 +11,8 @@
     <div class="comment-html" [innerHTML]="sanitizedCommentHTML"></div>
 
     <div class="comment-actions">
-      <div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply">Reply</div>
-      <div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete">Delete</div>
+      <div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply" i18n>Reply</div>
+      <div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete" i18n>Delete</div>
     </div>
 
     <my-video-comment-add
index 114a56dc77030357ef283a8d73feaa342250a6f1..ac7c03648032b5a8eb69f5f1017eb5760b8a2859 100644 (file)
@@ -3,7 +3,10 @@
     <div class="title-page title-page-single">
       Comments
     </div>
-    <my-help *ngIf="video.commentsEnabled === true" helpType="custom" customHtml="You can either comment on the page of your instance where this video is federated with your PeerTube account, or via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box <strong>@{{video.account.displayName}}@{{video.account.host}}</strong> and find back the video. Direct commenting capabilities are being worked on in <a href='https://github.com/Chocobozzz/PeerTube/issues/224'>#224</a>."></my-help>
+    <my-help
+      *ngIf="video.commentsEnabled === true" helpType="custom" i18n-customHtml
+      customHtml="You can either comment on the page of your instance where this video is federated with your PeerTube account, or via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box <strong>@{{video.account.displayName}}@{{video.account.host}}</strong> and find back the video. Direct commenting capabilities are being worked on in <a href='https://github.com/Chocobozzz/PeerTube/issues/224'>#224</a>."
+    ></my-help>
   </div>
 
   <ng-template [ngIf]="video.commentsEnabled === true">
@@ -14,7 +17,7 @@
       (commentCreated)="onCommentThreadCreated($event)"
     ></my-video-comment-add>
 
-    <div *ngIf="componentPagination.totalItems === 0 && comments.length === 0">No comments.</div>
+    <div *ngIf="componentPagination.totalItems === 0 && comments.length === 0" i18n>No comments.</div>
 
     <div
       class="comment-threads"
     >
       <div *ngIf="highlightedThread" id="highlighted-comment">
         <my-video-comment
-            [comment]="highlightedThread"
-            [video]="video"
-            [inReplyToCommentId]="inReplyToCommentId"
-            [commentTree]="threadComments[highlightedThread.id]"
-            [highlightedComment]="true"
-            (wantedToReply)="onWantedToReply($event)"
-            (wantedToDelete)="onWantedToDelete($event)"
-            (threadCreated)="onThreadCreated($event)"
-            (resetReply)="onResetReply()"
+          [comment]="highlightedThread"
+          [video]="video"
+          [inReplyToCommentId]="inReplyToCommentId"
+          [commentTree]="threadComments[highlightedThread.id]"
+          [highlightedComment]="true"
+          (wantedToReply)="onWantedToReply($event)"
+          (wantedToDelete)="onWantedToDelete($event)"
+          (threadCreated)="onThreadCreated($event)"
+          (resetReply)="onResetReply()"
         ></my-video-comment>
       </div>
 
@@ -50,7 +53,7 @@
         ></my-video-comment>
 
         <div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies">
-          View all {{ comment.totalReplies }} replies
+          <ng-container i18n>View all {{ comment.totalReplies }} replies</ng-container>
 
           <span *ngIf="!threadLoading[comment.id]" class="glyphicon glyphicon-menu-down"></span>
           <my-loader class="comment-thread-loading" [loading]="threadLoading[comment.id]"></my-loader>
@@ -59,7 +62,7 @@
     </div>
   </ng-template>
 
-  <div *ngIf="video.commentsEnabled === false">
+  <div *ngIf="video.commentsEnabled === false" i18n>
     Comments are disabled.
   </div>
 </div>
index 34f4a0701774d0d4079e5012429a762de98e857c..8c6ddb89e511955146f2f9ffdb3daed32cfb66c6 100644 (file)
@@ -11,6 +11,7 @@ import { VideoSortField } from '../../../shared/video/sort-field.type'
 import { VideoDetails } from '../../../shared/video/video-details.model'
 import { VideoComment } from './video-comment.model'
 import { VideoCommentService } from './video-comment.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-comments',
@@ -40,7 +41,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
     private videoCommentService: VideoCommentService,
-    private activatedRoute: ActivatedRoute
+    private activatedRoute: ActivatedRoute,
+    private i18n: I18n
   ) {}
 
   ngOnInit () {
@@ -77,7 +79,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
           if (highlightThread) this.highlightedThread = new VideoComment(res.comment)
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
@@ -89,7 +91,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
           this.componentPagination.totalItems = res.totalComments
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
@@ -111,9 +113,11 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
 
   async onWantedToDelete (commentToDelete: VideoComment) {
     let message = 'Do you really want to delete this comment?'
-    if (commentToDelete.totalReplies !== 0) message += `${commentToDelete.totalReplies} would be deleted too.`
+    if (commentToDelete.totalReplies !== 0) {
+      message += this.i18n(' {{ totalReplies }} replies will be deleted too.', { totalReplies: commentToDelete.totalReplies })
+    }
 
-    const res = await this.confirmService.confirm(message, 'Delete')
+    const res = await this.confirmService.confirm(message, this.i18n('Delete'))
     if (res === false) return
 
     this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)
@@ -136,7 +140,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
           this.componentPagination.totalItems--
         },
 
-        err => this.notificationsService.error('Error', err.message)
+        err => this.notificationsService.error(this.i18n('Error'), err.message)
       )
   }
 
index 617892b111ba97ed25238264d9c2f3c8231e5f83..d30a49345dc9ae2a4b3aed56efc487683bcedc3d 100644 (file)
@@ -4,7 +4,7 @@
 
       <div class="modal-header">
         <span class="close" aria-hidden="true" (click)="hide()"></span>
-        <h4 class="modal-title">Download video</h4>
+        <h4 i18n class="modal-title">Download video</h4>
       </div>
 
       <div class="modal-body">
         <div class="download-type">
           <div class="peertube-radio-container">
             <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent">
-            <label for="download-torrent">Torrent</label>
+            <label i18n for="download-torrent">Torrent</label>
           </div>
 
           <div class="peertube-radio-container">
             <input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct">
-            <label for="download-direct">Direct download</label>
+            <label i18n for="download-direct">Direct download</label>
           </div>
         </div>
 
         <div class="form-group inputs">
-          <span class="action-button action-button-cancel" (click)="hide()">
+          <span i18n class="action-button action-button-cancel" (click)="hide()">
             Cancel
           </span>
 
           <input
-            type="submit" value="Download" class="action-button-submit"
+            type="submit" i18n-value value="Download" class="action-button-submit"
             (click)="download()"
           >
         </div>
index a9a7beb481ca9b436d444c1945c4a32f2e6a8fd5..4ee3721fbce2770134a8ab448b0edfe4ed89e8c9 100644 (file)
@@ -4,14 +4,14 @@
 
       <div class="modal-header">
         <span class="close" aria-hidden="true" (click)="hide()"></span>
-        <h4 class="modal-title">Report video</h4>
+        <h4 i18n class="modal-title">Report video</h4>
       </div>
 
       <div class="modal-body">
 
         <form novalidate [formGroup]="form" (ngSubmit)="report()">
           <div class="form-group">
-            <textarea placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }">
+            <textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }">
             </textarea>
             <div *ngIf="formErrors.reason" class="form-error">
               {{ formErrors.reason }}
           </div>
 
           <div class="form-group inputs">
-            <span class="action-button action-button-cancel" (click)="hide()">
+            <span i18n class="action-button action-button-cancel" (click)="hide()">
               Cancel
             </span>
 
             <input
-              type="submit" value="Submit" class="action-button-submit"
+              type="submit" i18n-value value="Submit" class="action-button-submit"
               [disabled]="!form.valid"
             >
           </div>
index 050e827e7656141ae18fad55fff249d25ffae50d..1bbd3022638c2a2d234faed134d0c0c764bd11ae 100644 (file)
@@ -4,6 +4,7 @@ import { NotificationsService } from 'angular2-notifications'
 import { ModalDirective } from 'ngx-bootstrap/modal'
 import { FormReactive, VIDEO_ABUSE_REASON, VideoAbuseService } from '../../../shared/index'
 import { VideoDetails } from '../../../shared/video/video-details.model'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-report',
@@ -27,8 +28,9 @@ export class VideoReportComponent extends FormReactive implements OnInit {
   constructor (
     private formBuilder: FormBuilder,
     private videoAbuseService: VideoAbuseService,
-    private notificationsService: NotificationsService
-   ) {
+    private notificationsService: NotificationsService,
+    private i18n: I18n
+  ) {
     super()
   }
 
@@ -58,11 +60,11 @@ export class VideoReportComponent extends FormReactive implements OnInit {
     this.videoAbuseService.reportVideo(this.video.id, reason)
                           .subscribe(
                             () => {
-                              this.notificationsService.success('Success', 'Video reported.')
+                              this.notificationsService.success(this.i18n('Success'), this.i18n('Video reported.'))
                               this.hide()
                             },
 
-                            err => this.notificationsService.error('Error', err.message)
+                            err => this.notificationsService.error(this.i18n('Error'), err.message)
                            )
   }
 }
index 85cf10a6cfdddf5e8df0cafde6279323b7ca5bb1..26ab5144ab0a334dbfc7f5d3dae2cf8dc48e3a25 100644 (file)
@@ -4,12 +4,12 @@
 
       <div class="modal-header">
         <span class="close" aria-hidden="true" (click)="hide()"></span>
-        <h4 class="modal-title">Share</h4>
+        <h4 i18n class="modal-title">Share</h4>
       </div>
 
       <div class="modal-body">
         <div class="form-group">
-          <label>URL</label>
+          <label i18n>URL</label>
           <div class="input-group input-group-sm">
             <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoUrl()" />
             <div class="input-group-btn" placement="bottom right">
@@ -21,7 +21,7 @@
         </div>
 
         <div class="form-group">
-          <label>Embed</label>
+          <label i18n>Embed</label>
           <div class="input-group input-group-sm">
             <input #shareInput (click)="shareInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoIframeCode()" />
             <div class="input-group-btn" placement="bottom right">
           </div>
         </div>
 
-        <div *ngIf="notSecure()" class="alert alert-warning">
+        <div i18n *ngIf="notSecure()" class="alert alert-warning">
           The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
         </div>
 
         <div class="form-group inputs">
-          <span class="action-button action-button-cancel" (click)="hide()">
+          <span i18n class="action-button action-button-cancel" (click)="hide()">
             Cancel
           </span>
         </div>
index 33998c5d804d7f91232da019d065732055bec237..5c988a43b51fb3797d7a53ce116b8cc6bdd1189e 100644 (file)
@@ -5,6 +5,7 @@ import { NotificationsService } from 'angular2-notifications'
 import { ModalDirective } from 'ngx-bootstrap/modal'
 import { VideoDetails } from '../../../shared/video/video-details.model'
 import { buildVideoEmbed } from '../../../../assets/player/utils'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-video-share',
@@ -16,7 +17,10 @@ export class VideoShareComponent {
 
   @ViewChild('modal') modal: ModalDirective
 
-  constructor (private notificationsService: NotificationsService) {
+  constructor (
+    private notificationsService: NotificationsService,
+    private i18n: I18n
+  ) {
     // empty
   }
 
@@ -41,6 +45,6 @@ export class VideoShareComponent {
   }
 
   activateCopiedMessage () {
-    this.notificationsService.success('Success', 'Copied')
+    this.notificationsService.success(this.i18n('Success'), this.i18n('Copied'))
   }
 }
index 16ad9502a2d43ab19170f9d222b0cf36d4cd5cd2..9bcfcea477c71e6c162e941f51e90f8e39685a5a 100644 (file)
@@ -4,7 +4,7 @@
 
       <div class="modal-header">
         <span class="close" aria-hidden="true" (click)="hide()"></span>
-        <h4 class="modal-title">Support</h4>
+        <h4 i18n class="modal-title">Support</h4>
       </div>
 
       <div class="modal-body">
@@ -12,7 +12,7 @@
         <div [innerHTML]="videoHTMLSupport"></div>
 
         <div class="form-group inputs">
-          <span class="action-button action-button-cancel" (click)="hide()">
+          <span i18n class="action-button action-button-cancel" (click)="hide()">
             Cancel
           </span>
         </div>
index 03568b618d4781f80f7b9aedf2e7de39a0329745..2fd82a94065d368cc9892b6a1e41237db7c21616 100644 (file)
@@ -27,8 +27,8 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
     protected notificationsService: NotificationsService,
     protected authService: AuthService,
     protected location: Location,
-    private videoService: VideoService,
-    private i18n: I18n
+    protected i18n: I18n,
+    private videoService: VideoService
   ) {
     super()
 
index 5768d9fe0c8a2853db270927d008c7e78328204b..8183357f87bd0d0b450b062c153d8fe09bf79001 100644 (file)
@@ -25,8 +25,8 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
     protected location: Location,
     protected notificationsService: NotificationsService,
     protected authService: AuthService,
-    private videoService: VideoService,
-    private i18n: I18n
+    protected i18n: I18n,
+    private videoService: VideoService
   ) {
     super()
 
index 35566a7bd9d05574f8b971b91260e2349f81279f..b6434f3476cbdead09e3e09c94ba8a24273aa8f0 100644 (file)
@@ -31,9 +31,9 @@ export class VideoSearchComponent extends AbstractVideoList implements OnInit, O
     protected notificationsService: NotificationsService,
     protected authService: AuthService,
     protected location: Location,
+    protected i18n: I18n,
     private videoService: VideoService,
-    private redirectService: RedirectService,
-    private i18n: I18n
+    private redirectService: RedirectService
   ) {
     super()
 
index 760470e8c24721787eefd5993c5938b53cc30856..e56b749d11dc9db38ae2ca6801a985f47e0c3823 100644 (file)
@@ -25,8 +25,8 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
     protected notificationsService: NotificationsService,
     protected authService: AuthService,
     protected location: Location,
-    private videoService: VideoService,
-    private i18n: I18n
+    protected i18n: I18n,
+    private videoService: VideoService
   ) {
     super()
 
index 6c355a97fca4049e375d76bfe9faeb22dc9ac8b5..7a7db4cd96d31c0fc75f97f1b01dbdb6b1662bb7 100644 (file)
@@ -2,7 +2,376 @@
 <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
   <file source-language="en-US" datatype="plaintext" original="ng2.template">
     <body>
-      <trans-unit id="298cb43759c99e11e2ca5f92c768a145ddaa323f" datatype="html">
+      <trans-unit id="17a9d3860d9ad593dd09a9f934e03999d9e76a7a" datatype="html">
+        <source>
+            Cancel
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/core/confirm/confirm.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">72</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-videos/my-account-videos.component.ts</context>
+          <context context-type="linenumber">27</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-support.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-download.component.ts</context>
+          <context context-type="linenumber">30</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-share.component.ts</context>
+          <context context-type="linenumber">40</context>
+        </context-group>
+      </trans-unit><trans-unit id="9d5f16f0233b39fa2cd843321407a7358c323ad8" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/&gt; - &lt;x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/&gt; views</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/shared/video/video-miniature.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+      </trans-unit><trans-unit id="28f86ffd419b869711aa13f5e5ff54be6d70731c" datatype="html">
+        <source>Edit</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/shared/misc/edit-button.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="961a134583d6256df39fbc520d020ebc48e3128d" datatype="html">
+        <source>Truncated preview</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/shared/forms/markdown-textarea.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+      </trans-unit><trans-unit id="f82f53a2544638939a8ba93c0fb1b0a4419c3196" datatype="html">
+        <source>Complete preview</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/shared/forms/markdown-textarea.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+      </trans-unit><trans-unit id="9c71feb04c2beab559f79c41c6127815fb9c1a6f" datatype="html">
+        <source>Get help</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/shared/misc/help.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit><trans-unit id="12910217fdcdbca64bee06f511639b653d5428ea" datatype="html">
+        <source>
+    Login
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
+        <source>User</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="51ef29329faccb28d94369897068897d1b3d0478" datatype="html">
+        <source>Username or email address</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">13</context>
+        </context-group>
+      </trans-unit><trans-unit id="02c4360c2d956e74ed6bb1f71e86812af0e19b87" datatype="html">
+        <source>
+          or create an account
+        </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">16</context>
+        </context-group>
+      </trans-unit><trans-unit id="d6290381021b16febc426d3e3a52dda83991ce0b" datatype="html">
+        <source>
+          or create an account on another instance
+        </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="76e1f485e6ead4c84b606f46d413878881d66ad3" datatype="html">
+        <source>User registration is not allowed on this instance, but you can register on many others!</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">26</context>
+        </context-group>
+      </trans-unit><trans-unit id="c32ef07f8803a223a83ed17024b38e8d82292407" datatype="html">
+        <source>Password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">36</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">39</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">47</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">49</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">30</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">30</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">28</context>
+        </context-group>
+      </trans-unit><trans-unit id="b87e81682959464211443afc3e23c506865d2eda" datatype="html">
+        <source>I forgot my password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">42</context>
+        </context-group>
+      </trans-unit><trans-unit id="d2eb6c5d41f70d4b8c0937e7e19e196143b47681" datatype="html">
+        <source>Forgot your password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">59</context>
+        </context-group>
+      </trans-unit><trans-unit id="244aae9346da82b0922506c2d2581373a15641cc" datatype="html">
+        <source>Email</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">64</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">36</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">38</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit><trans-unit id="69b6ac577a19acc39fc0c22342092f327fff2529" datatype="html">
+        <source>Email address</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">66</context>
+        </context-group>
+      </trans-unit><trans-unit id="78be69e4d26b3b654c49962839d8545e61bf8b55" datatype="html">
+        <source>Send me an email to reset my password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/login/login.component.ts</context>
+          <context context-type="linenumber">77</context>
+        </context-group>
+      </trans-unit><trans-unit id="2ba14c37f3b23553b2602c5e535d0ff4916f24aa" datatype="html">
+        <source>
+    Reset my password
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="7f3bdcce4b2e8c37cd7f0f6c92ef8cff34b039b8" datatype="html">
+        <source>Confirm password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+      </trans-unit><trans-unit id="3652e5c6e33165264d5271d06cc04ab7123b6df1" datatype="html">
+        <source>Confirmed password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit><trans-unit id="8bdf8db5eeeaef83184b489b80c1557b516fb3c3" datatype="html">
+        <source>Reset my password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">29</context>
+        </context-group>
+      </trans-unit><trans-unit id="4499806949402133d08a5029cb5462c5ea25336d" datatype="html">
+        <source>
+    Create an account
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="a6807b834e01ce165aa61fad157b0ff4288b6bf1" datatype="html">
+        <source>Initial video quota:</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+      </trans-unit><trans-unit id="87b6b2c26215c5e712d3bfe4cc86ba53bc23451c" datatype="html">
+        <source>
+      Unlimited
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">16</context>
+        </context-group>
+      </trans-unit><trans-unit id="08c74dc9762957593b91f6eb5d65efdfc975bf48" datatype="html">
+        <source>Username</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">25</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">27</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+      </trans-unit><trans-unit id="717a5e3574fec754fbeb348c2d5561c4d81facc4" datatype="html">
+        <source>Signup</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/signup/signup.component.ts</context>
+          <context context-type="linenumber">57</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">23</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">86</context>
+        </context-group>
+      </trans-unit><trans-unit id="b244b11c7b831849f726d9c296c7bc521289da0d" datatype="html">
+        <source>
+    Welcome to the &lt;x id="INTERPOLATION" equiv-text="{{ instanceName }}"/&gt; instance
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="eec715de352a6b114713b30b640d319fa78207a0" datatype="html">
+        <source>Description</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/account-about/account-about.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">32</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channel-about/video-channel-about.component.ts</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">23</context>
+        </context-group>
+      </trans-unit><trans-unit id="69580f2c2dbf4edf7096820ba8c393367352d774" datatype="html">
+        <source>Terms</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+      </trans-unit><trans-unit id="9c6e6db693ab265457c6578df179c65694141d27" datatype="html">
+        <source>User registration is allowed and</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">26</context>
+        </context-group>
+      </trans-unit><trans-unit id="3e95271e48614f5ac9e6444ea3b04e9de778ec4c" datatype="html">
+        <source>
+        this instance provides a baseline quota of &lt;x id="INTERPOLATION" equiv-text="{{ userVideoQuota | bytes: 0 }}"/&gt; space for the videos of its users.
+      </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">28</context>
+        </context-group>
+      </trans-unit><trans-unit id="6c497bd25bf8829521526deb51322b381146576a" datatype="html">
+        <source>
+        this instance provides unlimited space for the videos of its users.
+      </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">32</context>
+        </context-group>
+      </trans-unit><trans-unit id="b209efa206b87af23b39497ba45fe45391541336" datatype="html">
+        <source>
+      User registration is currently not allowed.
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">37</context>
+        </context-group>
+      </trans-unit><trans-unit id="c02493cfa08b82c468233b83069b5baff23890e1" datatype="html">
+        <source>P2P &amp; Privacy</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+      </trans-unit><trans-unit id="9a45f58e4a91f090034b12d70dad90c54a3baf5b" datatype="html">
+        <source>
+      PeerTube uses the BitTorrent protocol to share bandwidth between users. It implies that your public IP address is stored in the public BitTorrent tracker of the video PeerTube instance as long as you&apos;re watching the video.
+      If you want to keep your public IP address private, please use a VPN or Tor.
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/about/about.component.ts</context>
+          <context context-type="linenumber">45</context>
+        </context-group>
+      </trans-unit><trans-unit id="298cb43759c99e11e2ca5f92c768a145ddaa323f" datatype="html">
         <source>
            My public profile
           </source>
           <context context-type="sourcefile">app/menu/menu.component.ts</context>
           <context context-type="linenumber">17</context>
         </context-group>
-      </trans-unit><trans-unit id="5f60990802486b7906b422d80aace6a1b19dcc02" datatype="html">
-        <source>Video not found :&apos;(</source>
+      </trans-unit><trans-unit id="eee05612e26cfe9527f08c6e74df7dfd84880ae9" datatype="html">
+        <source>
+            My settings
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit><trans-unit id="6326f9ce2365bfe97668c4aa146fbbb762497c1a" datatype="html">
+        <source>
+            Log out
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">25</context>
+        </context-group>
+      </trans-unit><trans-unit id="6765b4c916060f6bc42d9bb69e80377dbcb5e4e9" datatype="html">
+        <source>Login</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">34</context>
+        </context-group>
+      </trans-unit><trans-unit id="d207cc1965ec0c29e594e0e9917f39bfc276ed87" datatype="html">
+        <source>Create an account</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">35</context>
+        </context-group>
+      </trans-unit><trans-unit id="a52dae09be10ca3a65da918533ced3d3f4992238" datatype="html">
+        <source>Videos</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">39</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/accounts.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channels.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit><trans-unit id="b6b7986bc3721ac483baf20bc9a320529075c807" datatype="html">
+        <source>Trending</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">43</context>
+        </context-group>
+      </trans-unit><trans-unit id="8d20c5f5dd30acbe71316544dab774393fd9c3c1" datatype="html">
+        <source>Recently added</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">48</context>
+        </context-group>
+      </trans-unit><trans-unit id="eadc17c3df80143992e2d9028dead3199ae6d79d" datatype="html">
+        <source>Local</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">53</context>
+        </context-group>
+      </trans-unit><trans-unit id="b7648e7aced164498aa843b5c4e8f2f1c36a7919" datatype="html">
+        <source>Administration</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">62</context>
+        </context-group>
+      </trans-unit><trans-unit id="004b222ff9ef9dd4771b777950ca1d0e4cd4348a" datatype="html">
+        <source>About</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/menu/menu.component.ts</context>
+          <context context-type="linenumber">67</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/accounts.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channels.component.ts</context>
+          <context context-type="linenumber">23</context>
+        </context-group>
+      </trans-unit><trans-unit id="8aa58cf00d949c509df91c621ab38131df0a7599" datatype="html">
+        <source>Search...</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/header/header.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="4b3972c3e9485218508a95f7a4ce7758e3f09ced" datatype="html">
+        <source>Upload</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/header/header.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+      </trans-unit><trans-unit id="c31161d1661884f54fbc5635aad5ce8d4803897e" datatype="html">
+        <source>No results.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/video-list/video-trending.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/video-list/video-recently-added.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/video-list/video-local.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/video-list/video-search.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/account-videos/account-videos.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-videos/my-account-videos.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channel-videos/video-channel-videos.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="a835d8a12e14eb96919245a0bbafd8069c146578" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ account.followersCount }}"/&gt; subscribers</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/accounts.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+      </trans-unit><trans-unit id="6f5a458f827503ac7b8697688ecf3e0490818ee8" datatype="html">
+        <source>Video channels</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/accounts.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+      </trans-unit><trans-unit id="299f97b8ee9c62d45f2cc01961aa1e5101d6d05a" datatype="html">
+        <source>Stats</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/account-about/account-about.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channel-about/video-channel-about.component.ts</context>
+          <context context-type="linenumber">16</context>
+        </context-group>
+      </trans-unit><trans-unit id="8bc634cd9d8c9b684dbfaaf17a522f894bedbffc" datatype="html">
+        <source>Joined &lt;x id="INTERPOLATION" equiv-text="{{ account.createdAt | date }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/account-about/account-about.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+      </trans-unit><trans-unit id="8fef247fd0c5bf790151f7661cafc4b7fd0397f3" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ videoChannel.followersCount }}"/&gt; subscribers</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/account-video-channels/account-video-channels.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channels.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="f36bd6a1570cb9b0a5023870f35160957cad2a8f" datatype="html">
+        <source>See this video channel</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+accounts/account-video-channels/account-video-channels.component.ts</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+      </trans-unit><trans-unit id="ff78f059449d44322f627d0f66df07abe476962b" datatype="html">
+        <source>Instance</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="cff1428d10d59d14e45edec3c735a27b5482db59" datatype="html">
+        <source>Name</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+      </trans-unit><trans-unit id="512b045163a7187b2fc5d554e5f59fb3e49e174b" datatype="html">
+        <source>Short description</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit><trans-unit id="554488d11165f38b27b8fe230aba8a2e30d57003" datatype="html">
+        <source>Default client route</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">54</context>
+        </context-group>
+      </trans-unit><trans-unit id="1cbeb1eb589bfbe5efce94184cacd3095ca26948" datatype="html">
+        <source>Videos Trending</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">57</context>
+        </context-group>
+      </trans-unit><trans-unit id="1861c96217213992e02dcb77e15ea69e718c9883" datatype="html">
+        <source>Videos Recently Added</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">58</context>
+        </context-group>
+      </trans-unit><trans-unit id="b6307f83d9f43bff8d5129a7888e89964ddc3f7f" datatype="html">
+        <source>Local videos</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">59</context>
+        </context-group>
+      </trans-unit><trans-unit id="8551afadb69b3fef89e191f507e8ac84e624e8b9" datatype="html">
+        <source>Policy on videos containing sensitive content</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">68</context>
+        </context-group>
+      </trans-unit><trans-unit id="aa3ef567a1ea22c1e4d0acfdc8f80bc636bf12df" datatype="html">
+        <source>With &lt;strong&gt;Do not list&lt;/strong&gt; or &lt;strong&gt;Blur thumbnails&lt;/strong&gt;, a confirmation will be requested to watch the video.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">71</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">6</context>
+        </context-group>
+      </trans-unit><trans-unit id="5e155c34fb3ed8159bf0a486a366cfbc6874f9fe" datatype="html">
+        <source>Do not list</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">76</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="aaa900149c2ca1575ac1918d1ded33fb69830ab2" datatype="html">
+        <source>Blur thumbnails</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">77</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+      </trans-unit><trans-unit id="010d24ef3c43b2d8f45a4d6cba7d73e12ee1557e" datatype="html">
+        <source>Display</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">78</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">13</context>
+        </context-group>
+      </trans-unit><trans-unit id="ca53e66e68986546b7ef820c934145fd7c9c4247" datatype="html">
+        <source>Signup enabled</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">92</context>
+        </context-group>
+      </trans-unit><trans-unit id="68bda70e0dd4f7f91549462e55f1b2a1602d8402" datatype="html">
+        <source>Signup limit</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">96</context>
+        </context-group>
+      </trans-unit><trans-unit id="ca2283fc765b9f44b69f0175d685dc2443da6011" datatype="html">
+        <source>Administrator</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">106</context>
+        </context-group>
+      </trans-unit><trans-unit id="55a0f51e38679d3141841e8333da5779d349c587" datatype="html">
+        <source>Admin email</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">109</context>
+        </context-group>
+      </trans-unit><trans-unit id="4d13a9cd5ed3dcee0eab22cb25198d43886942be" datatype="html">
+        <source>Users</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">119</context>
+        </context-group>
+      </trans-unit><trans-unit id="31b3275d999af45fe64c6824e6e017d2e2704f09" datatype="html">
+        <source>User default video quota</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">122</context>
+        </context-group>
+      </trans-unit><trans-unit id="99cb827741e93125476a0f5b676372d85d15b5fc" datatype="html">
+        <source>Twitter</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">138</context>
+        </context-group>
+      </trans-unit><trans-unit id="7fdb41bbf2ee042ec5f68725a1c16a1c97f3e524" datatype="html">
+        <source>Your Twitter username</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">141</context>
+        </context-group>
+      </trans-unit><trans-unit id="6e671e839ca889feef0d8ed525d1a44b4b10870c" datatype="html">
+        <source>Indicates the Twitter account for the website or platform on which the content was published.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">144</context>
+        </context-group>
+      </trans-unit><trans-unit id="c0716c28b9d4c9e0b2fd6031334394214e5f9605" datatype="html">
+        <source>Instance whitelisted by Twitter</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">159</context>
+        </context-group>
+      </trans-unit><trans-unit id="3f008a1a07ca42c6ad258fde1bbd80ed74ada19b" datatype="html">
+        <source>If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.&lt;br /&gt;
+If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.&lt;br /&gt;&lt;br /&gt;
+Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on &lt;a target=&apos;_blank&apos; rel=&apos;noopener noreferrer&apos; href=&apos;https://cards-dev.twitter.com/validator&apos;&gt;https://cards-dev.twitter.com/validator&lt;/a&gt; to see if you instance is whitelisted.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">162</context>
+        </context-group>
+      </trans-unit><trans-unit id="fe22d2c0020e913ee4b75ec22a3abc8814810490" datatype="html">
+        <source>Transcoding</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">172</context>
+        </context-group>
+      </trans-unit><trans-unit id="fca29003c4ea1226ff8cbee89481758aab0e2be9" datatype="html">
+        <source>Transcoding enabled</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">178</context>
+        </context-group>
+      </trans-unit><trans-unit id="a33feadefbb776217c2db96100736314f8b765c2" datatype="html">
+        <source>Transcoding threads</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">184</context>
+        </context-group>
+      </trans-unit><trans-unit id="6aff7f4b4f140702c4ce791cc9990932623862f0" datatype="html">
+        <source>Resolution &lt;x id="INTERPOLATION" equiv-text="{{ resolution }}"/&gt; enabled</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">203</context>
+        </context-group>
+      </trans-unit><trans-unit id="1fa92c6ce274f878b2625587daa7e08b2a3a8b38" datatype="html">
+        <source>Cache</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">207</context>
+        </context-group>
+      </trans-unit><trans-unit id="48c189b718ed2d091e5c515bfc14b03e5ceb4f93" datatype="html">
+        <source>Preview cache size</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">210</context>
+        </context-group>
+      </trans-unit><trans-unit id="bf91318659ada3d3ad1b0ca1e63ae427e5a857d5" datatype="html">
+        <source>Previews are not federated. We fetch them directly from the origin instance and cache them.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">213</context>
+        </context-group>
+      </trans-unit><trans-unit id="e3a65df2560e99864bbde695da3a7bdf743a184c" datatype="html">
+        <source>Customizations</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">225</context>
+        </context-group>
+      </trans-unit><trans-unit id="0da9752916950ce6890d897b835c923a71ad9c5c" datatype="html">
+        <source>JavaScript</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">228</context>
+        </context-group>
+      </trans-unit><trans-unit id="fda2339a6e6ba017ee43b560caf660ed4022333c" datatype="html">
+        <source>Write directly JavaScript code.&lt;br /&gt;Example: &lt;pre&gt;console.log(&apos;my instance is amazing&apos;);&lt;/pre&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">231</context>
+        </context-group>
+      </trans-unit><trans-unit id="f133b08d6519081bfb8ef51cff4bf2b3af23dde6" datatype="html">
+        <source>
+              Write directly CSS code. Example:&lt;br /&gt;
+              &lt;pre&gt;
+    body &lt;x id="INTERPOLATION" equiv-text="{{ &apos;{&apos; }}"/&gt;
+      background-color: red;
+    &lt;x id="INTERPOLATION_1" equiv-text="{{ &apos;}&apos; }}"/&gt;
+              &lt;/pre&gt;
+
+              Prepend with &lt;em&gt;#custom-css&lt;/em&gt; to override styles. Example:
+              &lt;pre&gt;
+    #custom-css .logged-in-email &lt;x id="INTERPOLATION" equiv-text="{{ &apos;{&apos; }}"/&gt;
+      color: red;
+    &lt;x id="INTERPOLATION_1" equiv-text="{{ &apos;}&apos; }}"/&gt;
+              &lt;/pre&gt;
+            </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">247</context>
+        </context-group>
+      </trans-unit><trans-unit id="dad5a5283e4c853c011a0f03d5a52310338bbff8" datatype="html">
+        <source>Update configuration</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">274</context>
+        </context-group>
+      </trans-unit><trans-unit id="80dbb8ba42b97a9ec035c0ba09f45c07ea07096c" datatype="html">
+        <source>
+      Users
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/admin.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="0315abd64e35510ed0534f597130ef781aca175a" datatype="html">
+        <source>
+      Manage follows
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/admin.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="1c9406213cf05033eda4d3df678217b5eb822315" datatype="html">
+        <source>
+      Video abuses
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/admin.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="96ccede058f0022f34230c3adc09e60076b6d037" datatype="html">
+        <source>
+      Video blacklist
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/admin.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="7bea88c54fdccfdc9f687b0ffe9bf6a653d19368" datatype="html">
+        <source>
+      Jobs
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/admin.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+      </trans-unit><trans-unit id="9c6ce37623b626a102002901ca12c37e7a3a7f13" datatype="html">
+        <source>
+      Configuration
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/admin.component.ts</context>
+          <context context-type="linenumber">23</context>
+        </context-group>
+      </trans-unit><trans-unit id="4e8635c108375983b42229df44bda8c0af84f396" datatype="html">
+        <source>1 host (without &quot;http://&quot;) per line</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">5</context>
+        </context-group>
+      </trans-unit><trans-unit id="f7a7a00999ccbd126cbb8e74f5dd1724942dd507" datatype="html">
+        <source>
+    It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit><trans-unit id="456c6383d8e7cd15aadbcdc196d4ae7a70092437" datatype="html">
+        <source>Add following</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit><trans-unit id="45cc8ca94b5a50842a9a8ef804a5ab089a38ae5c" datatype="html">
+        <source>ID</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">18</context>
+        </context-group>
+      </trans-unit><trans-unit id="380e20a1e13d9489c69f6dbea7da19025ab6eb25" datatype="html">
+        <source>Score</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+      </trans-unit><trans-unit id="fe22ca53e651df951dac25b67c17894b0980f767" datatype="html">
+        <source>Host</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+      </trans-unit><trans-unit id="873b72903b1858a9cd6c8967521030b4d7d1435b" datatype="html">
+        <source>State</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="ff3173170e5b03536dd3b3e1afbae1f55356eb1b" datatype="html">
+        <source>Created &lt;x id="START_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;p-sortIcon&gt;"/&gt;<x id="CLOSE_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;/p-sortIcon&gt;"/></source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">13</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">16</context>
+        </context-group>
+      </trans-unit><trans-unit id="5fccee488a9ea908c16d2ab9dbdaf264f1aac479" datatype="html">
+        <source>Manage follows</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/follows/follows.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="a9f2501fcb2ff71f1376c2d2fbbbd49f200e6c8f" datatype="html">
+        <source>Jobs list</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="f61c6867295f3b53d23557021f2f4e0aa1d0b8fc" datatype="html">
+        <source>Type</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+      </trans-unit><trans-unit id="9da0107a35751e722c8b4bca7636fc7645dbdbdc" datatype="html">
+        <source>Updated</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">22</context>
+        </context-group>
+      </trans-unit><trans-unit id="31cf824034489eb42f6a388d5980b98b8e1de015" datatype="html">
+        <source>Create user</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">6</context>
+        </context-group>
+      </trans-unit><trans-unit id="2788d9a67ed2b6f35c85818e6af1871317c57a7e" datatype="html">
+        <source>Edit user &lt;x id="INTERPOLATION" equiv-text="{{ username }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="1bd571d8f3981f6043b0df3402cc3d97e0d7ad2a" datatype="html">
+        <source>john</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">10</context>
+        </context-group>
+      </trans-unit><trans-unit id="bb3542ff8e5defa6d0c773799e5c8fe399605d05" datatype="html">
+        <source>mail@example.com</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+      </trans-unit><trans-unit id="c36a66f2107e8da5371ebc9d15c2008dff567f46" datatype="html">
+        <source>Role</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">41</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">41</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+      </trans-unit><trans-unit id="15f046007e4fca2e8477966745e2ec4e3e81bc3b" datatype="html">
+        <source>Video quota</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">56</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">56</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">18</context>
+        </context-group>
+      </trans-unit><trans-unit id="42e3c0e89177ca135974221eaf0e4e836c32e345" datatype="html">
+        <source>
+      Transcoding is enabled on server. The video quota only take in account &lt;x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/&gt;original<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> video. <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/>
+      At most, this user could use ~ &lt;x id="INTERPOLATION" equiv-text="{{ computeQuotaWithTranscoding() | bytes: 0 }}"/&gt;.
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">65</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">65</context>
+        </context-group>
+      </trans-unit><trans-unit id="5e8b4663c17c337a1f11160c0a683350936faa1f" datatype="html">
+        <source>Users list</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="08ea8692dc2a7050026df26fc39b22960bde9de5" datatype="html">
+        <source>Username &lt;x id="START_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;p-sortIcon&gt;"/&gt;<x id="CLOSE_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;/p-sortIcon&gt;"/></source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">16</context>
+        </context-group>
+      </trans-unit><trans-unit id="0c7e8870481f1287af6a142f538391d8c16c2408" datatype="html">
+        <source>Video abuses list</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="4ba250869daa372b54d24fafc0ea934769ee4076" datatype="html">
+        <source>Reason</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="2bf5a31043ff476ca081a4080f3f3f17518dc6f2" datatype="html">
+        <source>Reporter</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+      </trans-unit><trans-unit id="2d1ea268a6a9f483dbc2cbfe19bf4256a57a6af4" datatype="html">
+        <source>Video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit><trans-unit id="c6ab75e099e131d7a4f94e1732e7436d8fc386c7" datatype="html">
+        <source>Go to the account</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">22</context>
+        </context-group>
+      </trans-unit><trans-unit id="1cb8348c199d03e297d165e262237194f25fe3f5" datatype="html">
+        <source>Go to the video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">28</context>
+        </context-group>
+      </trans-unit><trans-unit id="00ecde6001106fe7406a34cc3459cc5b88e4aec1" datatype="html">
+        <source>Blacklisted videos</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="7c02d113e9b7884037834cddecf2a32a5538b35b" datatype="html">
+        <source>Name &lt;x id="START_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;p-sortIcon&gt;"/&gt;<x id="CLOSE_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;/p-sortIcon&gt;"/></source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="cd5ca5da9e2fa21571e9f86a24a5c3b45a3ddc51" datatype="html">
+        <source>Views &lt;x id="START_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;p-sortIcon&gt;"/&gt;<x id="CLOSE_TAG_P-SORTICON" ctype="x-p-sortIcon" equiv-text="&lt;/p-sortIcon&gt;"/></source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">13</context>
+        </context-group>
+      </trans-unit><trans-unit id="d4717113115ca7106a354a5aac54d1c0126261d9" datatype="html">
+        <source>NSFW</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit><trans-unit id="8c87d9527af7ff2ada84c911516a9e43a352e401" datatype="html">
+        <source>UUID</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="86f26b106c67be3c2e98b82766656e5d9da86dff" datatype="html">
+        <source>Unblacklist</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">30</context>
+        </context-group>
+      </trans-unit><trans-unit id="efad4be364b8fb5c73cbfcc7acccd542f9d84ad6" datatype="html">
+        <source>My settings</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="520d68b2c9f7dacaf2a5073716cad9bd328ea7e7" datatype="html">
+        <source>My video channels</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account.component.ts</context>
+          <context context-type="linenumber">5</context>
+        </context-group>
+      </trans-unit><trans-unit id="d02888c485d3aeab6de628508f4a00312a722894" datatype="html">
+        <source>My videos</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="7cadf30b337f4ef9b05b7d02e13ec3cf79de9dba" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ user.account?.followersCount }}"/&gt; subscribers</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+      </trans-unit><trans-unit id="3fb9a5f7268114445d8c109a8f48102e93471f5a" datatype="html">
+        <source>Change your avatar</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit><trans-unit id="c860c88df9ad58b1187084251340b232cdf0a7f9" datatype="html">
+        <source>(extensions: &lt;x id="INTERPOLATION" equiv-text="{{ avatarExtensions }}"/&gt;, max size: &lt;x id="INTERPOLATION_1" equiv-text="{{ maxAvatarSize | bytes }}"/&gt;)</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit><trans-unit id="9518d3fb042d551167c1701ddeb88a1374cf1e48" datatype="html">
+        <source>Video quota:</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="994363f08f9fbfa3b3994ff7b35c6904fdff18d8" datatype="html">
+        <source>Profile</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+      </trans-unit><trans-unit id="b5398623f87ee72ed23f5023918db1707771e925" datatype="html">
+        <source>Video settings</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">31</context>
+        </context-group>
+      </trans-unit><trans-unit id="8057bddbed23d6cd911df8cc3a4ec24d1f258b79" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ video.createdAt | myFromNow }}"/&gt; - &lt;x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/&gt; views</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-videos/my-account-videos.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="a475a4862efc4e473d6201f09b258e05d651c1df" datatype="html">
+        <source>
+            &lt;x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span&gt;"/&gt;<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>
+            Delete
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-videos/my-account-videos.component.ts</context>
+          <context context-type="linenumber">31</context>
+        </context-group>
+      </trans-unit><trans-unit id="73c1cefc348a6f361497210dea1ed79499fd1260" datatype="html">
+        <source>Create another video channel</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+      </trans-unit><trans-unit id="30fcac6c20aac1f24e000efc4a889cbb93d4baf2" datatype="html">
+        <source>Go to the channel</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="9dbe4718a5611fbc611fc6b5e0b27df813372c68" datatype="html">
+        <source>Create a video channel</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit><trans-unit id="9277e6f7b8ed9538d1f6ad812b620384252ffe56" datatype="html">
+        <source>Update &lt;x id="INTERPOLATION" equiv-text="{{ videoChannel?.displayName }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="bc155f9fc3be3f32083f19b2c77d4ad3b696d9b9" datatype="html">
+        <source>Display name</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts</context>
+          <context context-type="linenumber">5</context>
+        </context-group>
+      </trans-unit><trans-unit id="74728de5289ea2ff3f553bc2b48f1811680b931a" datatype="html">
+        <source>Short text to tell people how they can support your channel (membership platform...).&lt;br /&gt;&lt;br /&gt;
+When you will upload a video in this channel, the video support field will be automatically filled by this text.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">32</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">32</context>
+        </context-group>
+      </trans-unit><trans-unit id="739516c2ca75843d5aec9cf0e6b3e4335c4227b9" datatype="html">
+        <source>Change password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">5</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">19</context>
+        </context-group>
+      </trans-unit><trans-unit id="e70e209561583f360b1e9cefd2cbb1fe434b6229" datatype="html">
+        <source>New password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="ede41f01c781b168a783cfcefc6fb67d48780d9b" datatype="html">
+        <source>Confirm new password</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="20f62f24170d57b1efeb2387a0949f482cd4d129" datatype="html">
+        <source>Default policy on videos containing sensitive content</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="fb17c44abac2d1ed2a54cdd28bae289dc0b9a1c2" datatype="html">
+        <source>Automatically plays video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+      </trans-unit><trans-unit id="52c9a103b812f258bcddc3d90a6e3f46871d25fe" datatype="html">
+        <source>Save</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">27</context>
+        </context-group>
+      </trans-unit><trans-unit id="d2fa66a905b6b7f691c83be681d18188cbe4a8ba" datatype="html">
+        <source>Update my profile</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts</context>
+          <context context-type="linenumber">23</context>
+        </context-group>
+      </trans-unit><trans-unit id="e242e3e8608a3c4a944327eb3d5c221dc6e4e3cd" datatype="html">
+        <source>
+  Sorry, but we couldn&apos;t find the page you were looking for.
+</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+page-not-found/page-not-found.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit><trans-unit id="c65641c36859c328928e6b0f14c3f913886f8add" datatype="html">
+        <source>Created by &lt;x id="INTERPOLATION" equiv-text="{{ videoChannel.ownerBy }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channels.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit><trans-unit id="e006ed166ce188cab168e1ca90435b33d042d913" datatype="html">
+        <source>Go the owner account page</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channels.component.ts</context>
+          <context context-type="linenumber">13</context>
+        </context-group>
+      </trans-unit><trans-unit id="1380539d91f77f565de6e21ce210da891e6644b8" datatype="html">
+        <source>Support this channel</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channel-about/video-channel-about.component.ts</context>
+          <context context-type="linenumber">9</context>
+        </context-group>
+      </trans-unit><trans-unit id="5523952d0300c96cfba2ec5a693c95f923e90c40" datatype="html">
+        <source>Created &lt;x id="INTERPOLATION" equiv-text="{{ videoChannel.createdAt | date }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/+video-channels/video-channel-about/video-channel-about.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit><trans-unit id="d4dcf74163f127ca9afa84d55b5d95846958faa0" datatype="html">
+        <source>Upload your video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">3</context>
+        </context-group>
+      </trans-unit><trans-unit id="1af3dcf5aad5b7f4b3251da88a89dc9a184445dd" datatype="html">
+        <source>Upload &lt;x id="INTERPOLATION" equiv-text="{{ videoFileName }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+      </trans-unit><trans-unit id="21add64f0f3ebbedf1150ca822c6e149494ab7a9" datatype="html">
+        <source>Select the file to upload</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+      </trans-unit><trans-unit id="0cc554f4d7bb6a87515d2d95438e183b50702071" datatype="html">
+        <source>Channel</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">35</context>
+        </context-group>
+      </trans-unit><trans-unit id="3c78b53bca33467190c0b7a01320bc093a2b1427" datatype="html">
+        <source>Privacy</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">26</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">86</context>
+        </context-group>
+      </trans-unit><trans-unit id="f7ac2376749c7985f94f0fc89ba75ea624de1215" datatype="html">
+        <source>Publish will be available when upload is finished</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">52</context>
+        </context-group>
+      </trans-unit><trans-unit id="223aae0477f79f0bc4436c1c57619415f04cbbb3" datatype="html">
+        <source>Publish</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">59</context>
+        </context-group>
+      </trans-unit><trans-unit id="fdf7cbdc140d0aab0f0b6c06065a0fd448ed6a2e" datatype="html">
+        <source>Title</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
+        <source>Tags</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="935e7146fe6c12169abfda18536c5856935cfd82" datatype="html">
+        <source>(press Enter to add)</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="50f53834157770b8205ada0e7a6e235211e4765e" datatype="html">
+        <source>Video descriptions are truncated by default and require manual action to expand them.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+      </trans-unit><trans-unit id="607de17c2a755f65775881c19e276e7c933bcf94" datatype="html">
+        <source>Category</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">44</context>
+        </context-group>
+      </trans-unit><trans-unit id="78d6d3ea26777cd0dad8ddbf9b314151678da46c" datatype="html">
+        <source>Licence</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">58</context>
+        </context-group>
+      </trans-unit><trans-unit id="fe46ccaae902ce974e2441abe752399288298619" datatype="html">
+        <source>Language</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">72</context>
+        </context-group>
+      </trans-unit><trans-unit id="5ef7108218e096d09f4ee8525a05a8c90d7b95ee" datatype="html">
+        <source>This video contains mature or explicit content</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">102</context>
+        </context-group>
+      </trans-unit><trans-unit id="73743a7cbb03abe81de0960a6bc4b6c42c18633a" datatype="html">
+        <source>Some instances do not list NSFW videos by default.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">103</context>
+        </context-group>
+      </trans-unit><trans-unit id="3549ee96125a43181f80712ed744ee223a0e645a" datatype="html">
+        <source>Enable video comments</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">109</context>
+        </context-group>
+      </trans-unit><trans-unit id="1dd793abd1cb8d16a7a2cb71ca5549a7111ee513" datatype="html">
+        <source>Upload thumbnail</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">119</context>
+        </context-group>
+      </trans-unit><trans-unit id="9df3f57e251c077bef7e7da81677cb971c55b639" datatype="html">
+        <source>Upload preview</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">126</context>
+        </context-group>
+      </trans-unit><trans-unit id="b5629d298ff1a69b8db19a4ba2995c76b52da604" datatype="html">
+        <source>Support</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">132</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-support.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">53</context>
+        </context-group>
+      </trans-unit><trans-unit id="f61f989de6fc12f99369a90800e4b5462d3f10a0" datatype="html">
+        <source>Short text to tell people how they can support you (membership platform...).</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-edit.component.ts</context>
+          <context context-type="linenumber">133</context>
+        </context-group>
+      </trans-unit><trans-unit id="c07377d8b52fde03fcf70824a980346b9222d056" datatype="html">
+        <source>(extensions: &lt;x id="INTERPOLATION" equiv-text="{{ videoImageExtensions }}"/&gt;, max size: &lt;x id="INTERPOLATION_1" equiv-text="{{ maxVideoImageSize | bytes }}"/&gt;)</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/shared/video-image.component.ts</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit><trans-unit id="2335f0bd17c63d835b50cfbbcea6c459cb1314c0" datatype="html">
+        <source>
+    Update &lt;x id="INTERPOLATION" equiv-text="{{ video?.name }}"/&gt;
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-update.component.ts</context>
+          <context context-type="linenumber">2</context>
+        </context-group>
+      </trans-unit><trans-unit id="047f50bc5b5d17b5bec0196355953e1a5c590ddb" datatype="html">
+        <source>Update</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-edit/video-update.component.ts</context>
+          <context context-type="linenumber">16</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">87</context>
+        </context-group>
+      </trans-unit><trans-unit id="9aafb2a928664aa7a9375fd37c533f0375f8b611" datatype="html">
+        <source>Download video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-download.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="b92eaf680d6d1cd83e1bc61c3ee88b1b7754eb66" datatype="html">
+        <source>Torrent</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-download.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="8d6a41c2703bed3edfc76e1df0b1ca203404c17c" datatype="html">
+        <source>Direct download</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-download.component.ts</context>
+          <context context-type="linenumber">25</context>
+        </context-group>
+      </trans-unit><trans-unit id="dc75033a5238fdc4f462212c847a45ba8018a3fd" datatype="html">
+        <source>Download</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-download.component.ts</context>
+          <context context-type="linenumber">35</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">69</context>
+        </context-group>
+      </trans-unit><trans-unit id="11749f4fc0aa1b5e37f38575e4d4e3b1b7e0e96b" datatype="html">
+        <source>Report video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-report.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+      </trans-unit><trans-unit id="bb44873ad8d4c5dbad0ac2a6a50e0ceee9119125" datatype="html">
+        <source>Reason...</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-report.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit><trans-unit id="0e6b8229bd65f93bc8040d0fb598967f220740c7" datatype="html">
+        <source>
+              Cancel
+            </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-report.component.ts</context>
+          <context context-type="linenumber">22</context>
+        </context-group>
+      </trans-unit><trans-unit id="71c77bb8cecdf11ec3eead24dd1ba506573fa9cd" datatype="html">
+        <source>Submit</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-report.component.ts</context>
+          <context context-type="linenumber">27</context>
+        </context-group>
+      </trans-unit><trans-unit id="0bd8b27f60a1f098a53e06328426d818e3508ff9" datatype="html">
+        <source>Share</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-share.component.ts</context>
+          <context context-type="linenumber">7</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">58</context>
+        </context-group>
+      </trans-unit><trans-unit id="801b98c6f02fe3b32f6afa3ee854c99ed83474e6" datatype="html">
+        <source>URL</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-share.component.ts</context>
+          <context context-type="linenumber">12</context>
+        </context-group>
+      </trans-unit><trans-unit id="d3b15c3bf4a7ea38d6002d2d2c4781642d30e79c" datatype="html">
+        <source>Embed</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-share.component.ts</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+      </trans-unit><trans-unit id="239fe0316cfe91aa6e1e7bf1ef19e3b7772131f8" datatype="html">
+        <source>
+          The url is not secured (no HTTPS), so the embed video won&apos;t work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
+        </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/modal/video-share.component.ts</context>
+          <context context-type="linenumber">35</context>
+        </context-group>
+      </trans-unit><trans-unit id="5f60990802486b7906b422d80aace6a1b19dcc02" datatype="html">
+        <source>Video not found :&apos;(</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">6</context>
+        </context-group>
+      </trans-unit><trans-unit id="643ab402461b1169eebbe2ed790e12a9a83551aa" datatype="html">
+        <source>
+            &lt;x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/&gt; - &lt;x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/&gt; views
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="5cb397241041f7ad70997806227bafcdf7eb1b33" datatype="html">
+        <source>Go the channel page</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="912f005563d20191efc188dccedd35a7c4e6b396" datatype="html">
+        <source>You can subscribe to this account via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box &lt;strong&gt;@&lt;x id="INTERPOLATION" equiv-text="{{video.account.displayName}}"/&gt;@&lt;x id="INTERPOLATION_1" equiv-text="{{video.account.host}}"/&gt;&lt;/strong&gt; and subscribe there. Subscription as a PeerTube user is being worked on in &lt;a href=&apos;https://github.com/Chocobozzz/PeerTube/issues/470&apos;&gt;#470&lt;/a&gt;.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">24</context>
+        </context-group>
+      </trans-unit><trans-unit id="ccc07df383b7a32be3e2e105faa5488caf261c1c" datatype="html">
+        <source>By &lt;x id="INTERPOLATION" equiv-text="{{ video.by }}"/&gt;</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">29</context>
+        </context-group>
+      </trans-unit><trans-unit id="e88300c71e0cb0f346d5a72eb37c920f2aadae8a" datatype="html">
+        <source>Go the account page</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">28</context>
+        </context-group>
+      </trans-unit><trans-unit id="82b59049f3f89d900c98da9319e156dd513e3ced" datatype="html">
+        <source>Like this video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">41</context>
+        </context-group>
+      </trans-unit><trans-unit id="623698f075025b2b2fc2e0c59fd95f4f4662a509" datatype="html">
+        <source>Dislike this video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">48</context>
+        </context-group>
+      </trans-unit><trans-unit id="144fff5c40b85414d59e644d8dee7cfefba925a2" datatype="html">
+        <source>Download the video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">68</context>
+        </context-group>
+      </trans-unit><trans-unit id="f72992030f134408b675152c397f9d0ec00f3b2a" datatype="html">
+        <source>Report</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">75</context>
+        </context-group>
+      </trans-unit><trans-unit id="2f4894617d9c44010f87473e583bd4604b7d6ecf" datatype="html">
+        <source>Report this video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">74</context>
+        </context-group>
+      </trans-unit><trans-unit id="007ab5fa2aae8a7372307d3fc45a2dbcb11ffd61" datatype="html">
+        <source>Blacklist</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">81</context>
+        </context-group>
+      </trans-unit><trans-unit id="803c6317abd2dbafcc93226c4e273c62932e3037" datatype="html">
+        <source>Blacklist this video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">80</context>
+        </context-group>
+      </trans-unit><trans-unit id="cd27f761b923a5bdb16ba9844da632edd878f1b1" datatype="html">
+        <source>Update this video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">86</context>
+        </context-group>
+      </trans-unit><trans-unit id="826b25211922a1b46436589233cb6f1a163d89b7" datatype="html">
+        <source>Delete</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">93</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comment.component.ts</context>
+          <context context-type="linenumber">15</context>
+        </context-group>
+      </trans-unit><trans-unit id="3dbfdc68f83d91cb360172eb65578cae94e7cbe5" datatype="html">
+        <source>Delete this video</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">92</context>
+        </context-group>
+      </trans-unit><trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
+        <source>Show more</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">112</context>
+        </context-group>
+      </trans-unit><trans-unit id="5403a767248e304199592271bba3366d2ca3f903" datatype="html">
+        <source>Show less</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">118</context>
+        </context-group>
+      </trans-unit><trans-unit id="8057a9b7f9e908ff350edfd71417b96c174e5911" datatype="html">
+        <source>
+            Privacy
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">125</context>
+        </context-group>
+      </trans-unit><trans-unit id="bd407eca607a8905a26a9e30c9d0cd70f4465db8" datatype="html">
+        <source>
+            Category
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">134</context>
+        </context-group>
+      </trans-unit><trans-unit id="af5072bd79ea3cd767ab74a6622d2eee791b3832" datatype="html">
+        <source>
+            Licence
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">143</context>
+        </context-group>
+      </trans-unit><trans-unit id="a911eee019174741b0aec6fcf3fbd5752fab3e67" datatype="html">
+        <source>
+            Language
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">152</context>
+        </context-group>
+      </trans-unit><trans-unit id="ecf7007c2842cc26a7b91d08d48c7a4f5f749fb3" datatype="html">
+        <source>
+            Tags
+          </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">161</context>
+        </context-group>
+      </trans-unit><trans-unit id="7ce8b0d7cc34d4c1ef4a21e990b0a001337bedd1" datatype="html">
+        <source>
+        Other videos
+      </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">175</context>
+        </context-group>
+      </trans-unit><trans-unit id="fb779d2b25c4d0ffa7d52c823a240717e8c1fe6c" datatype="html">
+        <source>Friendly Reminder:</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">187</context>
+        </context-group>
+      </trans-unit><trans-unit id="4c2fca29fd9d7e85abe85a206958a4226f403be2" datatype="html">
+        <source>
+        The sharing system used by this video implies that some technical information about your system (such as a public IP address) can be accessed publicly.
+      </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">189</context>
+        </context-group>
+      </trans-unit><trans-unit id="e60c11e1b1dfbbeda577364b8de39ded2d796c5e" datatype="html">
+        <source>More information</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">192</context>
+        </context-group>
+      </trans-unit><trans-unit id="bd499ca7913bb5408fd139a4cb4f863852d5f318" datatype="html">
+        <source>Get more information</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">192</context>
+        </context-group>
+      </trans-unit><trans-unit id="20fc98888baf65b5ba9fe9622dc036fa8dec6a5f" datatype="html">
+        <source>
+      OK
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">195</context>
+        </context-group>
+      </trans-unit><trans-unit id="4b1a394a3d619606f79b1051b1493e6b743a072d" datatype="html">
+        <source>You can either comment on the page of your instance where this video is federated with your PeerTube account, or via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box &lt;strong&gt;@&lt;x id="INTERPOLATION" equiv-text="{{video.account.displayName}}"/&gt;@&lt;x id="INTERPOLATION_1" equiv-text="{{video.account.host}}"/&gt;&lt;/strong&gt; and find back the video. Direct commenting capabilities are being worked on in &lt;a href=&apos;https://github.com/Chocobozzz/PeerTube/issues/224&apos;&gt;#224&lt;/a&gt;.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">8</context>
+        </context-group>
+      </trans-unit><trans-unit id="17810e68b0ba21e62e61eecfaf0a93b2c91033b4" datatype="html">
+        <source>No comments.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">20</context>
+        </context-group>
+      </trans-unit><trans-unit id="69c081796209e45e26af91152ec9bd0a65ec261e" datatype="html">
+        <source>View all &lt;x id="INTERPOLATION" equiv-text="{{ comment.totalReplies }}"/&gt; replies</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">56</context>
+        </context-group>
+      </trans-unit><trans-unit id="b7fccd922d6473725247ed85a9fdf96fe6794828" datatype="html">
+        <source>
+    Comments are disabled.
+  </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">65</context>
+        </context-group>
+      </trans-unit><trans-unit id="db79255cb8757e9e945ba5f901a2b67e4189016e" datatype="html">
+        <source>Add comment...</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comment-add.component.ts</context>
+          <context context-type="linenumber">6</context>
+        </context-group>
+      </trans-unit><trans-unit id="26fa50ba8e69b53162b348d98e25f8b76c81343e" datatype="html">
+        <source>
+      Post comment
+    </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comment-add.component.ts</context>
+          <context context-type="linenumber">17</context>
+        </context-group>
+      </trans-unit><trans-unit id="a607fab03e11b0e07c1640e11a1b02d7af06b285" datatype="html">
+        <source>Highlighted comment</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comment.component.ts</context>
+          <context context-type="linenumber">5</context>
+        </context-group>
+      </trans-unit><trans-unit id="cb23d4d98007aa4d7123837f4c17a671848377d6" datatype="html">
+        <source>Reply</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">app/videos/+video-watch/comment/video-comment.component.ts</context>
+          <context context-type="linenumber">14</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="37b56526e384f843a15323dc730b484a97b4c968" datatype="html">
+        <source>No description</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+accounts/account-about/account-about.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+video-channels/video-channel-about/video-channel-about.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="2f03e577e8f81a9f8be0095f93e1f9376c6eedc9" datatype="html">
+        <source>Published videos</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+accounts/account-videos/account-videos.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="b0ea97653991a80d6324423949d37b8f165a4505" datatype="html">
+        <source>Published &lt;x id="INTERPOLATION" equiv-text="{{ totalVideos }}"/&gt; videos</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+accounts/account-videos/account-videos.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="6080b77234e92ad41bb52653b239c4c4f851317d" datatype="html">
+        <source>Error</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/followers-list/followers-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/jobs/jobs-list/jobs-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/core/auth/auth.service.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/login/login.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/comment/video-comment-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/comment/video-comments.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/modal/video-report.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="6b988bab9e171f65ed3510e8a66b9c5f7fcc5209" datatype="html">
+        <source>You set custom &lt;x id="INTERPOLATION" equiv-text="{{ customizationsText }}"/&gt;. </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="865bc18d22e223101ede0916967ead0abd515d0e" datatype="html">
+        <source>This could lead to security issues or bugs if you do not understand it. </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="262e18b2efb5912651684a522fc08d77c99972d0" datatype="html">
+        <source>Are you sure you want to update the configuration?</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="03b6bae23e3f895ed8f53e3b29fad0cafc7dd002" datatype="html">
+        <source>Please type &quot;I understand the &lt;x id="INTERPOLATION" equiv-text="{{ customizationsText }}"/&gt; I set&quot; to confirm.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="892eb3bbce40125f9ed1dc13078d2938b921ff53" datatype="html">
+        <source>I understand the &lt;x id="INTERPOLATION" equiv-text="{{ customizationsText }}"/&gt; I set</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1e035e6ccfab771cad4226b2ad230cb0d4a88cba" datatype="html">
+        <source>Success</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/login/login.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/signup/signup.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/modal/video-report.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/modal/video-share.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="b9e64712e3e5c342ce9cd32eec6cd7d6c00f4048" datatype="html">
+        <source>Configuration updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="511be2e1ddb087fe7a0d95654f5f72b446d3da87" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ host }}"/&gt; is not valid</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="e02f50674f1d96966384dc096beb42d4973997df" datatype="html">
+        <source>You need to specify hosts to follow.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="c2a114eb000e7c38e8ad4b1768821bdf6e946d71" datatype="html">
+        <source>Hosts need to be unique.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="a6718d6aaf5bcd1692eed48daa61d2bed62c1f50" datatype="html">
+        <source>If you confirm, you will send a follow request to:<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> - </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1266acb081ef0324c4a38ae2d514dd75d8b38409" datatype="html">
+        <source>Follow new server(s)</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="950f5111d567e5c0e971f07c26e8c2be1d919a8e" datatype="html">
+        <source>Follow request(s) sent!</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-add/following-add.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="b1f6b95a2d83bc589955f2679de00ce70fa03594" datatype="html">
+        <source>Do you really want to unfollow &lt;x id="INTERPOLATION" equiv-text="{{ host }}"/&gt;?</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="a89875525c82ab81ffe32e481a5475b43d0c2902" datatype="html">
+        <source>Unfollow</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="c02051988cf0b04bc8bea7602c909c4835ed770f" datatype="html">
+        <source>You are not following &lt;x id="INTERPOLATION" equiv-text="{{ host }}"/&gt; anymore.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/follows/following-list/following-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="fed7ccf455d8457dfe6b8650161b2ba991fc3162" datatype="html">
+        <source>User &lt;x id="INTERPOLATION" equiv-text="{{ username }}"/&gt; created.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-edit/user-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="047fa00d26afadba9a3c82453e653ba863ed048b" datatype="html">
+        <source>User &lt;x id="INTERPOLATION" equiv-text="{{ username }}"/&gt; updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="9910122dfedd2eaa544a990f1430e5b82a76d99f" datatype="html">
+        <source>Update user</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-edit/user-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="911fc197949e47aa5f0541627bc319f59edd9d11" datatype="html">
+        <source>You cannot delete root.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="9ef88654aab4b2df4fa2083f33caa0c5419c1a60" datatype="html">
+        <source>Do you really want to delete this user?</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="383611faadd7b4cf0bbc124d2e42b535fa6c2eb0" datatype="html">
+        <source>User &lt;x id="INTERPOLATION" equiv-text="{{ username }}"/&gt; deleted.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/users/user-list/user-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="4733ad1d7e63960438c0203b9a64f165b5fc84f2" datatype="html">
+        <source>Do you really want to remove this video from the blacklist ? It will be available again in the videos list.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="4255d5c12ab55f41866ad22453d4b70e0deab89f" datatype="html">
+        <source>Video &lt;x id="INTERPOLATION" equiv-text="{{ name }}"/&gt; removed from the blacklist.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="2db8f1f93a5485c32267762a3bf4da499832e732" datatype="html">
+        <source>The new password and the confirmed password do not correspond.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="19508af0dfbc685cbf10cf02061bb5a0f423b6fc" datatype="html">
+        <source>Password updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="db4ff52375f6a25ad0472e92754c8c265ae47c6b" datatype="html">
+        <source>Profile updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="aa6fb95c355f172bda303de1ce2f38c251a149cf" datatype="html">
+        <source>Unlimited</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="1e003ad599ef836949b9f4dad3037a58ef3ff8d1" datatype="html">
+        <source>Avatar changed.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="214b802dfd6f544003147a7a68938ec1055c8f32" datatype="html">
+        <source>Information updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="206542c1b57ce583f3cfe68b8609a0c4f791ae0c" datatype="html">
+        <source>Video channel &lt;x id="INTERPOLATION" equiv-text="{{ videoChannelName }}"/&gt; created.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
+        <source>Create</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8ad57f6504ec3c791c2fc07523053ae4bf12e63e" datatype="html">
+        <source>Video channel &lt;x id="INTERPOLATION" equiv-text="{{ videoChannelName }}"/&gt; updated.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="cb033ad5876fce7072bceb4eeba7d2154748153f" datatype="html">
+        <source>Do you really want to delete &lt;x id="INTERPOLATION" equiv-text="{{ videoChannelName }}"/&gt;? It will delete all videos uploaded in this channel too.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="703dee7f3e693f9c77ef17c46f9fa71999609f8e" datatype="html">
+        <source>Please type the name of the video channel to confirm</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="504b4bf7053bc5ac9853d4fd7aaa6b38703dcbd2" datatype="html">
+        <source>Video channel {{ videoChannelName } deleted.</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts</context>
+          <context context-type="linenumber">1</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="814d28bf9dcbd3122254e664b446ac8e0442bc08" datatype="html">
+        <source>Error getting about from server</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">6</context>
+          <context context-type="sourcefile">src/app/about/about.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="643ab402461b1169eebbe2ed790e12a9a83551aa" datatype="html">
-        <source>
-            &lt;x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/&gt; - &lt;x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/&gt; views
-          </source>
+      </trans-unit>
+      <trans-unit id="070558f351471e268ae7a690ba31ac0c1ead6d8f" datatype="html">
+        <source>Cannot retrieve OAuth Client credentials: &lt;x id="INTERPOLATION" equiv-text="{{ errorText }}"/&gt;.
+</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">15</context>
+          <context context-type="sourcefile">src/app/core/auth/auth.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="5cb397241041f7ad70997806227bafcdf7eb1b33" datatype="html">
-        <source>Go the channel page</source>
+      </trans-unit>
+      <trans-unit id="8d9b4f4b69108c3c9aa0f3b0dbde87786ba9b319" datatype="html">
+        <source>Ensure you have correctly configured PeerTube (config/ directory), in particular the &quot;webserver&quot; section.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">20</context>
+          <context context-type="sourcefile">src/app/core/auth/auth.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="912f005563d20191efc188dccedd35a7c4e6b396" datatype="html">
-        <source>You can subscribe to this account via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box &lt;strong&gt;@&lt;x id="INTERPOLATION" equiv-text="{{video.account.displayName}}"/&gt;@&lt;x id="INTERPOLATION_1" equiv-text="{{video.account.host}}"/&gt;&lt;/strong&gt; and subscribe there. Subscription as a PeerTube user is being worked on in &lt;a href=&apos;https://github.com/Chocobozzz/PeerTube/issues/470&apos;&gt;#470&lt;/a&gt;.</source>
+      </trans-unit>
+      <trans-unit id="e31bbf15d6ba5c7c0f17f89a98029cff0bd40b87" datatype="html">
+        <source>You need to reconnect.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">24</context>
+          <context context-type="sourcefile">src/app/core/auth/auth.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="ccc07df383b7a32be3e2e105faa5488caf261c1c" datatype="html">
-        <source>By &lt;x id="INTERPOLATION" equiv-text="{{ video.by }}"/&gt;</source>
+      </trans-unit>
+      <trans-unit id="68e710782ccb5398b3acb8844caf0b199da2c3da" datatype="html">
+        <source>Confirm</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">29</context>
+          <context context-type="sourcefile">src/app/core/confirm/confirm.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="e88300c71e0cb0f346d5a72eb37c920f2aadae8a" datatype="html">
-        <source>Go the account page</source>
+      </trans-unit>
+      <trans-unit id="4fe245955c7ec7d53a4236fda7a985edcb63124c" datatype="html">
+        <source>An email with the reset password instructions will be sent to &lt;x id="INTERPOLATION" equiv-text="{{ email }}"/&gt;.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">28</context>
+          <context context-type="sourcefile">src/app/login/login.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="82b59049f3f89d900c98da9319e156dd513e3ced" datatype="html">
-        <source>Like this video</source>
+      </trans-unit>
+      <trans-unit id="ccbf0490fb6b60d21e03bb2c9003df0ce1a58752" datatype="html">
+        <source>Unable to find user id or verification string.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">41</context>
+          <context context-type="sourcefile">src/app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="623698f075025b2b2fc2e0c59fd95f4f4662a509" datatype="html">
-        <source>Dislike this video</source>
+      </trans-unit>
+      <trans-unit id="b0f24b7136e551a0deba831f1525711245b31a26" datatype="html">
+        <source>Your password has been successfully reset!</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">48</context>
+          <context context-type="sourcefile">src/app/reset-password/reset-password.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="b5629d298ff1a69b8db19a4ba2995c76b52da604" datatype="html">
-        <source>Support</source>
+      </trans-unit>
+      <trans-unit id="0bf41abaa85526711f7952b4600e4044bc7f04a4" datatype="html">
+        <source>All unsaved data will be lost, are you sure you want to leave this page?</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">53</context>
+          <context context-type="sourcefile">src/app/shared/guards/can-deactivate-guard.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="0bd8b27f60a1f098a53e06328426d818e3508ff9" datatype="html">
-        <source>Share</source>
+      </trans-unit>
+      <trans-unit id="a8059e31694578c1b0344a76a345357dd60e8f01" datatype="html">
+        <source>Warning</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">58</context>
+          <context context-type="sourcefile">src/app/shared/guards/can-deactivate-guard.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="dc75033a5238fdc4f462212c847a45ba8018a3fd" datatype="html">
-        <source>Download</source>
+      </trans-unit>
+      <trans-unit id="4ae5829f2615ca2343280765e6b6adfb5cc41128" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; years ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">69</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="144fff5c40b85414d59e644d8dee7cfefba925a2" datatype="html">
-        <source>Download the video</source>
+      </trans-unit>
+      <trans-unit id="a2bada0a7274e74d4318cc86d413e3ae32f57bdd" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; months ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">68</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="f72992030f134408b675152c397f9d0ec00f3b2a" datatype="html">
-        <source>Report</source>
+      </trans-unit>
+      <trans-unit id="550f8907c0a4a636d494ed945f3c10dd3a58113a" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; month ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">75</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="2f4894617d9c44010f87473e583bd4604b7d6ecf" datatype="html">
-        <source>Report this video</source>
+      </trans-unit>
+      <trans-unit id="bcc068f243c2f21112b7559f88d1d599b94e2a46" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; weeks ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">74</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="007ab5fa2aae8a7372307d3fc45a2dbcb11ffd61" datatype="html">
-        <source>Blacklist</source>
+      </trans-unit>
+      <trans-unit id="a8ab22b7de1e4a70285fe7d06962a2140d5a5252" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; week ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">81</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="803c6317abd2dbafcc93226c4e273c62932e3037" datatype="html">
-        <source>Blacklist this video</source>
+      </trans-unit>
+      <trans-unit id="ca8bfebe411d4b56e2cfea8bd47346a7a51dea66" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; days ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">80</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="047f50bc5b5d17b5bec0196355953e1a5c590ddb" datatype="html">
-        <source>Update</source>
+      </trans-unit>
+      <trans-unit id="853e61e6ba27292056e756194829c5498387b381" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; day ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">87</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="cd27f761b923a5bdb16ba9844da632edd878f1b1" datatype="html">
-        <source>Update this video</source>
+      </trans-unit>
+      <trans-unit id="41d5a34bc1c27138d8ffbeecd7499f7854025f11" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; hours ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">86</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="826b25211922a1b46436589233cb6f1a163d89b7" datatype="html">
-        <source>Delete</source>
+      </trans-unit>
+      <trans-unit id="551090bafad6b52d4677e7d65fb10692b813945b" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; hour ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">93</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="3dbfdc68f83d91cb360172eb65578cae94e7cbe5" datatype="html">
-        <source>Delete this video</source>
+      </trans-unit>
+      <trans-unit id="5f751a2e17480da31cd12f8cac3e85a9a5ea9439" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; min ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">92</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
-        <source>Show more</source>
+      </trans-unit>
+      <trans-unit id="a3ac5cb5be93ff145b3bf0139fe20da052060c4c" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ interval }}"/&gt; sec ago</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">112</context>
+          <context context-type="sourcefile">src/app/shared/misc/from-now.pipe.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="5403a767248e304199592271bba3366d2ca3f903" datatype="html">
-        <source>Show less</source>
+      </trans-unit>
+      <trans-unit id="0c0f5bbcd2386018ec057877f9d3c5c2c9880cac" datatype="html">
+        <source>Request is too large for the server. Please contact you administrator if you want to increase the limit size.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">118</context>
+          <context context-type="sourcefile">src/app/shared/rest/rest-extractor.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="8057a9b7f9e908ff350edfd71417b96c174e5911" datatype="html">
-        <source>
-            Privacy
-          </source>
+      </trans-unit>
+      <trans-unit id="3d6b54e95d42ef7586fb88f535b8d0349d431745" datatype="html">
+        <source>Too many attempts, please try again after &lt;x id="INTERPOLATION" equiv-text="{{ minutesLeft }}"/&gt; minutes.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">125</context>
+          <context context-type="sourcefile">src/app/shared/rest/rest-extractor.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="bd407eca607a8905a26a9e30c9d0cd70f4465db8" datatype="html">
-        <source>
-            Category
-          </source>
+      </trans-unit>
+      <trans-unit id="ab783a52f2df9ff7a20139cab0da6d0764f3cc5d" datatype="html">
+        <source>Too many attempts, please try again later.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">134</context>
+          <context context-type="sourcefile">src/app/shared/rest/rest-extractor.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="af5072bd79ea3cd767ab74a6622d2eee791b3832" datatype="html">
-        <source>
-            Licence
-          </source>
+      </trans-unit>
+      <trans-unit id="0f286a597f0053c3578a52e044769c204ee516fc" datatype="html">
+        <source>Server error. Please retry later.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">143</context>
+          <context context-type="sourcefile">src/app/shared/rest/rest-extractor.service.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="a911eee019174741b0aec6fcf3fbd5752fab3e67" datatype="html">
-        <source>
-            Language
-          </source>
+      </trans-unit>
+      <trans-unit id="240f841426d253c459e739c19156f05d913ac10c" datatype="html">
+        <source>Registration for &lt;x id="INTERPOLATION" equiv-text="{{ username }}"/&gt; complete.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">152</context>
+          <context context-type="sourcefile">src/app/signup/signup.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="ecf7007c2842cc26a7b91d08d48c7a4f5f749fb3" datatype="html">
-        <source>
-            Tags
-          </source>
+      </trans-unit>
+      <trans-unit id="cb77327761a94def3c7c0c2362e3af9e5949f57b" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ seconds }}"/&gt; of full HD videos</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">161</context>
+          <context context-type="sourcefile">src/app/signup/signup.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="7ce8b0d7cc34d4c1ef4a21e990b0a001337bedd1" datatype="html">
-        <source>
-        Other videos
-      </source>
+      </trans-unit>
+      <trans-unit id="06dbb94903fc77f10c6760d7ebbb9cf649a0c8fd" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ seconds }}"/&gt; of HD videos</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">175</context>
+          <context context-type="sourcefile">src/app/signup/signup.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="fb779d2b25c4d0ffa7d52c823a240717e8c1fe6c" datatype="html">
-        <source>Friendly Reminder:</source>
+      </trans-unit>
+      <trans-unit id="d44fb1f436492c547bfb99825245526958dc84e7" datatype="html">
+        <source>&lt;x id="INTERPOLATION" equiv-text="{{ seconds }}"/&gt; of average quality videos</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">187</context>
+          <context context-type="sourcefile">src/app/signup/signup.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="4c2fca29fd9d7e85abe85a206958a4226f403be2" datatype="html">
-        <source>
-        The sharing system used by this video implies that some technical information about your system (such as a public IP address) can be accessed publicly.
-      </source>
+      </trans-unit>
+      <trans-unit id="1e876f14d96cdf3b334c080fe795a2e0ab53aa3a" datatype="html">
+        <source>Your video was uploaded in your account and is private.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">189</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="e60c11e1b1dfbbeda577364b8de39ded2d796c5e" datatype="html">
-        <source>More information</source>
+      </trans-unit>
+      <trans-unit id="24840228f2826b66252cfcaab9820b1c7e0da264" datatype="html">
+        <source>But associated data (tags, description...) will be lost, are you sure you want to leave this page?</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">192</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="bd499ca7913bb5408fd139a4cb4f863852d5f318" datatype="html">
-        <source>Get more information</source>
+      </trans-unit>
+      <trans-unit id="5af84926d631326e548573ebf0f6dff07845aeb4" datatype="html">
+        <source>Your video is not uploaded yet, are you sure you want to leave this page?</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">192</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
-      </trans-unit><trans-unit id="20fc98888baf65b5ba9fe9622dc036fa8dec6a5f" datatype="html">
-        <source>
-      OK
-    </source>
+      </trans-unit>
+      <trans-unit id="321e4419a943044e674beb55b8039f42a9761ca5" datatype="html">
+        <source>Info</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">app/videos/+video-watch/video-watch.component.ts</context>
-          <context context-type="linenumber">195</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
+          <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="23b2c2f4dd69e29c3bff00469e259dcb01de5633" datatype="html">
-        <source>Do you really want to blacklist this video?</source>
+      <trans-unit id="c5cb19aeb6447deda40cc1227ceca1359ab955e9" datatype="html">
+        <source>Upload cancelled</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="1e035e6ccfab771cad4226b2ad230cb0d4a88cba" datatype="html">
-        <source>Success</source>
+      <trans-unit id="8b7132ca8401e9b847c242dc9a6b63cc63a80a74" datatype="html">
+        <source>We are sorry but PeerTube cannot handle videos &gt; 4GB</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="d31d39e8ee9b2f20bffb3468ee062eaa5409c59f" datatype="html">
+        <source>Your video quota is exceeded with this video (video size: &lt;x id="INTERPOLATION" equiv-text="{{ videoSize }}"/&gt;, used: &lt;x id="INTERPOLATION_1" equiv-text="{{ videoQuotaUsed }}"/&gt;, quota: &lt;x id="INTERPOLATION_2" equiv-text="{{ videoQuota }}"/&gt;)</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="085d56464b75ae5c1e370f5290e4c4cf23961a61" datatype="html">
-        <source>Video &lt;x id="INTERPOLATION" equiv-text="{{ videoName }}"/&gt; had been blacklisted.</source>
+      <trans-unit id="972fc644f847cf84e4732ec012915c4cdaf865ce" datatype="html">
+        <source>Video published.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-add.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="6080b77234e92ad41bb52653b239c4c4f851317d" datatype="html">
-        <source>Error</source>
+      <trans-unit id="757e9c083c8f3d578bd74f055cc337c72417e187" datatype="html">
+        <source>Video updated.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-edit/video-update.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="36cd97a83cd16866213a1d16d1637a3639ec998f" datatype="html">
+        <source> &lt;x id="INTERPOLATION" equiv-text="{{ totalReplies }}"/&gt; replies will be deleted too.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-watch/comment/video-comments.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="fa2601e52cbf5725a13d33fe14458823b882ea50" datatype="html">
+        <source>Video reported.</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-watch/modal/video-report.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="ef90545bc832876c0d7f9a10363c75137472bbb5" datatype="html">
+        <source>Copied</source>
         <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
+          <context context-type="sourcefile">src/app/videos/+video-watch/modal/video-share.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="23b2c2f4dd69e29c3bff00469e259dcb01de5633" datatype="html">
+        <source>Do you really want to blacklist this video?</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
           <context context-type="linenumber">1</context>
         </context-group>
+      </trans-unit>
+      <trans-unit id="085d56464b75ae5c1e370f5290e4c4cf23961a61" datatype="html">
+        <source>Video &lt;x id="INTERPOLATION" equiv-text="{{ videoName }}"/&gt; had been blacklisted.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/videos/+video-watch/video-watch.component.ts</context>
           <context context-type="linenumber">1</context>
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="b6307f83d9f43bff8d5129a7888e89964ddc3f7f" datatype="html">
-        <source>Local videos</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/video-list/video-local.component.ts</context>
-          <context context-type="linenumber">1</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="8d20c5f5dd30acbe71316544dab774393fd9c3c1" datatype="html">
-        <source>Recently added</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/video-list/video-recently-added.component.ts</context>
-          <context context-type="linenumber">1</context>
-        </context-group>
-      </trans-unit>
       <trans-unit id="7e892ba15f2c6c17e83510e273b3e10fc32ea016" datatype="html">
         <source>Search</source>
         <context-group purpose="location">
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="b6b7986bc3721ac483baf20bc9a320529075c807" datatype="html">
-        <source>Trending</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/videos/video-list/video-trending.component.ts</context>
-          <context context-type="linenumber">1</context>
-        </context-group>
-      </trans-unit>
     </body>
   </file>
 </xliff>