Add i18n attributes

This commit is contained in:
Chocobozzz 2018-06-04 16:21:17 +02:00
parent 989e526abf
commit b1d40cff89
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
96 changed files with 3107 additions and 586 deletions

View 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>

View 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')
}
}

View 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>

View 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 () {

View 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>

View 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>

View 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 }}
@ -18,10 +18,10 @@
</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 }}
@ -29,10 +29,10 @@
</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 }}
@ -40,10 +40,10 @@
</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 }}
@ -51,12 +51,12 @@
</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">
@ -65,14 +65,17 @@
</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">
@ -80,43 +83,43 @@
</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">
@ -132,14 +135,17 @@
<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 }}
@ -150,29 +156,32 @@
<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>

View 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)
)
}

View 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>

View 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)
)
}
}

View 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>

View 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
}
}

View 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>

View 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)
)
}
}

View 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">

View File

@ -1 +1,4 @@
export * from './'
export * from './shared'
export * from './jobs-list'
export * from './job.routes'
export * from './job.component'

View 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()">
@ -15,11 +15,11 @@
<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>

View 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)
)
}

View 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)

View 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')
}
}

View 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>

View 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) {

View 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>
@ -13,11 +13,11 @@
>
<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>

View 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)
)
}
}

View 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>
@ -19,13 +19,13 @@
<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>

View 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)
)
}
}

View 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>

View 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)
)
}
}

View 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>

View 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
)

View 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>

View 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

View 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>

View 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)
)
}

View 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>

View 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)
)
}
}

View 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')
}
}

View 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

View 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')
}
}

View 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>
@ -12,13 +12,13 @@
</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">

View 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)
)
}

View File

@ -1,4 +1,4 @@
<div *ngIf="pagination.totalItems === 0">No results.</div>
<div i18n *ngIf="pagination.totalItems === 0">No results.</div>
<div
myInfiniteScroller
@ -17,18 +17,18 @@
<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>

View 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 () {

View 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">

View File

@ -1,3 +1,3 @@
<div>
<div i18n>
Sorry, but we couldn't find the page you were looking for.
</div>

View 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>

View 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')
}
}

View 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 () {

View 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>

View 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>

View 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)
)
}

View 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()

View 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>

View 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()
}

View 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>

View 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>
@ -33,13 +33,13 @@
</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 }}
@ -56,25 +56,25 @@
<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>

View 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)
)
}

View File

@ -18,11 +18,11 @@
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>
@ -31,26 +31,26 @@
</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>
@ -59,12 +59,12 @@
<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>

View 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 () {

View 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>

View 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' ])
},

View 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>

View 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({

View 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')
)
}

View 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>

View 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) })
}
}

View File

@ -15,6 +15,7 @@
<span
class="help-tooltip-button"
title="Get help"
i18n-title
[popover]="tooltipTemplate"
[placement]="tooltipPlacement"
[outsideClick]="true"

View 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.'

View 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"

View 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)
}
)
}

View 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>

View 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 }" />

View 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 }}
@ -13,18 +13,18 @@
<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>

View 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 />')

View 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>
@ -99,14 +99,14 @@
<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>
@ -116,24 +116,24 @@
<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 }}

View 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" />

View 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>
@ -49,14 +49,14 @@
></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>

View 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)
}
)

View 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>

View 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)
}
)

View 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>

View 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)
)
}

View 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

View 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"
@ -24,15 +27,15 @@
>
<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>

View 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)
)
}

View 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">
@ -17,22 +17,22 @@
<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>

View 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 }}
@ -19,12 +19,12 @@
</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>

View 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)
)
}
}

View 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">
@ -32,12 +32,12 @@
</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>

View 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'))
}
}

View 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>

View 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()

View 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()

View 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()

View 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()

File diff suppressed because it is too large Load Diff