Migrate to $localize

* Remove i18n polyfill to translate things in components
 * Reduce bundle sizes
 * Improve runtime perf
 * Reduce a lot the time to make a full client build
 * Reduce client build complexity
 * We don't need a service to translate things anymore (so we will be able to translate title pages etc)

Unfortunately we may loose some translations in the migration process.
I'll put a message on weblate to notify translators
This commit is contained in:
Chocobozzz 2020-08-12 10:40:04 +02:00
parent 8c36074799
commit 66357162f8
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
136 changed files with 1064 additions and 1631 deletions

View File

@ -124,6 +124,7 @@
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"aot": true, "aot": true,
"localize": true,
"outputPath": "dist", "outputPath": "dist",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
@ -214,6 +215,7 @@
"budgets": [] "budgets": []
}, },
"hmr": { "hmr": {
"localize": false,
"budgets": [ "budgets": [
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
@ -228,6 +230,7 @@
] ]
}, },
"e2e": { "e2e": {
"localize": false,
"budgets": [ "budgets": [
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
@ -240,84 +243,6 @@
"with": "src/environments/environment.e2e.ts" "with": "src/environments/environment.e2e.ts"
} }
] ]
},
"ar": {
"localize": [ "ar" ]
},
"hu-HU": {
"localize": [ "hu" ]
},
"th-TH": {
"localize": [ "th" ]
},
"fi-FI": {
"localize": [ "fi" ]
},
"nl-NL": {
"localize": [ "nl" ]
},
"gd": {
"localize": [ "gd" ]
},
"el-GR": {
"localize": [ "el" ]
},
"es-ES": {
"localize": [ "es" ]
},
"oc": {
"localize": [ "oc" ]
},
"pt-BR": {
"localize": [ "pt" ]
},
"pt-PT": {
"localize": [ "pt-PT" ]
},
"sv-SE": {
"localize": [ "sv" ]
},
"pl-PL": {
"localize": [ "pl" ]
},
"ru-RU": {
"localize": [ "ru" ]
},
"zh-Hans-CN": {
"localize": [ "zh-Hans" ]
},
"zh-Hant-TW": {
"localize": [ "zh-Hant" ]
},
"fr-FR": {
"localize": [ "fr" ]
},
"ja-JP": {
"localize": [ "ja" ]
},
"eu-ES": {
"localize": [ "eu" ]
},
"ca-ES": {
"localize": [ "ca" ]
},
"cs-CZ": {
"localize": [ "cs" ]
},
"eo": {
"localize": [ "eo" ]
},
"de-DE": {
"localize": [ "de" ]
},
"it-IT": {
"localize": [ "it" ]
},
"vi-VN": {
"localize": [ "vi" ]
},
"kab": {
"localize": [ "kab" ]
} }
} }
}, },

View File

@ -28,19 +28,19 @@
"typings": "*.d.ts", "typings": "*.d.ts",
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.1001.0-next.4", "@angular-devkit/build-angular": "^0.1001.0-next.4",
"@angular/animations": "^10.1.0-next.4", "@angular/animations": "^10.1.0-next.5",
"@angular/cdk": "^10.0.0", "@angular/cdk": "^10.0.0",
"@angular/cli": "^10.1.0-next.4", "@angular/cli": "^10.1.0-next.4",
"@angular/common": "^10.1.0-next.4", "@angular/common": "^10.1.0-next.5",
"@angular/compiler": "^10.1.0-next.4", "@angular/compiler": "^10.1.0-next.5",
"@angular/compiler-cli": "^10.1.0-next.4", "@angular/compiler-cli": "^10.1.0-next.5",
"@angular/core": "^10.1.0-next.4", "@angular/core": "^10.1.0-next.5",
"@angular/forms": "^10.1.0-next.4", "@angular/forms": "^10.1.0-next.5",
"@angular/localize": "^10.1.0-next.4", "@angular/localize": "^10.1.0-next.5",
"@angular/platform-browser": "^10.1.0-next.4", "@angular/platform-browser": "^10.1.0-next.5",
"@angular/platform-browser-dynamic": "^10.1.0-next.4", "@angular/platform-browser-dynamic": "^10.1.0-next.5",
"@angular/router": "^10.1.0-next.4", "@angular/router": "^10.1.0-next.5",
"@angular/service-worker": "^10.1.0-next.4", "@angular/service-worker": "^10.1.0-next.5",
"@angularclass/hmr": "^2.1.3", "@angularclass/hmr": "^2.1.3",
"@neos21/bootstrap3-glyphicons": "^1.0.1", "@neos21/bootstrap3-glyphicons": "^1.0.1",
"@ng-bootstrap/ng-bootstrap": "^7.0.0", "@ng-bootstrap/ng-bootstrap": "^7.0.0",
@ -51,7 +51,6 @@
"@ngx-loading-bar/http-client": "^5.0.0", "@ngx-loading-bar/http-client": "^5.0.0",
"@ngx-loading-bar/router": "^5.0.0", "@ngx-loading-bar/router": "^5.0.0",
"@ngx-meta/core": "^9.0.0", "@ngx-meta/core": "^9.0.0",
"@ngx-translate/i18n-polyfill": "^1.0.0",
"@types/chart.js": "^2.9.16", "@types/chart.js": "^2.9.16",
"@types/core-js": "^2.5.2", "@types/core-js": "^2.5.2",
"@types/debug": "^4.1.5", "@types/debug": "^4.1.5",

View File

@ -4,7 +4,6 @@ import { FormReactive, FormValidatorService, InstanceValidatorsService } from '@
import { InstanceService } from '@app/shared/shared-instance' import { InstanceService } from '@app/shared/shared-instance'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig } from '@shared/models' import { ServerConfig } from '@shared/models'
@Component({ @Component({
@ -26,8 +25,7 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
private instanceValidatorsService: InstanceValidatorsService, private instanceValidatorsService: InstanceValidatorsService,
private instanceService: InstanceService, private instanceService: InstanceService,
private serverService: ServerService, private serverService: ServerService,
private notifier: Notifier, private notifier: Notifier
private i18n: I18n
) { ) {
super() super()
} }
@ -70,13 +68,13 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
this.instanceService.contactAdministrator(fromEmail, fromName, subject, body) this.instanceService.contactAdministrator(fromEmail, fromName, subject, body)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Your message has been sent.')) this.notifier.success($localize`Your message has been sent.`)
this.hide() this.hide()
}, },
err => { err => {
this.error = err.status === 403 this.error = err.status === 403
? this.i18n('You already sent this form recently') ? $localize`You already sent this form recently`
: err.message : err.message
} }
) )

View File

@ -2,7 +2,6 @@ import { Subscription } from 'rxjs'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { MarkdownService } from '@app/core' import { MarkdownService } from '@app/core'
import { Account, AccountService } from '@app/shared/shared-main' import { Account, AccountService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-account-about', selector: 'my-account-about',
@ -16,7 +15,6 @@ export class AccountAboutComponent implements OnInit, OnDestroy {
private accountSub: Subscription private accountSub: Subscription
constructor ( constructor (
private i18n: I18n,
private accountService: AccountService, private accountService: AccountService,
private markdownService: MarkdownService private markdownService: MarkdownService
) { } ) { }
@ -37,6 +35,6 @@ export class AccountAboutComponent implements OnInit, OnDestroy {
getAccountDescription () { getAccountDescription () {
if (this.descriptionHTML) return this.descriptionHTML if (this.descriptionHTML) return this.descriptionHTML
return this.i18n('No description') return $localize`No description`
} }
} }

View File

@ -6,7 +6,6 @@ import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenServi
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { Account, AccountService, VideoService } from '@app/shared/shared-main' import { Account, AccountService, VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-account-videos', selector: 'my-account-videos',
@ -23,7 +22,6 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
private accountSub: Subscription private accountSub: Subscription
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -66,7 +64,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
.getAccountVideos(this.account, newPagination, this.sort) .getAccountVideos(this.account, newPagination, this.sort)
.pipe( .pipe(
tap(({ total }) => { tap(({ total }) => {
this.titlePage = this.i18n('Published {{total}} videos', { total }) this.titlePage = $localize`Published ${total} videos`
}) })
) )
} }

View File

@ -5,7 +5,6 @@ import { ActivatedRoute } from '@angular/router'
import { AuthService, Notifier, RedirectService, RestExtractor, ScreenService, UserService } from '@app/core' import { AuthService, Notifier, RedirectService, RestExtractor, ScreenService, UserService } from '@app/core'
import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
import { AccountReportComponent } from '@app/shared/shared-moderation' import { AccountReportComponent } from '@app/shared/shared-moderation'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { User, UserRight } from '@shared/models' import { User, UserRight } from '@shared/models'
@Component({ @Component({
@ -36,8 +35,7 @@ export class AccountsComponent implements OnInit, OnDestroy {
private restExtractor: RestExtractor, private restExtractor: RestExtractor,
private redirectService: RedirectService, private redirectService: RedirectService,
private authService: AuthService, private authService: AuthService,
private screenService: ScreenService, private screenService: ScreenService
private i18n: I18n
) { ) {
} }
@ -58,9 +56,9 @@ export class AccountsComponent implements OnInit, OnDestroy {
) )
this.links = [ this.links = [
{ label: this.i18n('VIDEO CHANNELS'), routerLink: 'video-channels' }, { label: $localize`VIDEO CHANNELS`, routerLink: 'video-channels' },
{ label: this.i18n('VIDEOS'), routerLink: 'videos' }, { label: $localize`VIDEOS`, routerLink: 'videos' },
{ label: this.i18n('ABOUT'), routerLink: 'about' } { label: $localize`ABOUT`, routerLink: 'about' }
] ]
} }
@ -88,11 +86,13 @@ export class AccountsComponent implements OnInit, OnDestroy {
} }
activateCopiedMessage () { activateCopiedMessage () {
this.notifier.success(this.i18n('Username copied')) this.notifier.success($localize`Username copied`)
} }
subscribersDisplayFor (count: number) { subscribersDisplayFor (count: number) {
return this.i18n('{count, plural, =1 {1 subscriber} other {{{count}} subscribers}}', { count }) if (count === 1) return $localize`1 subscriber`
return $localize`${count} subscribers`
} }
private onAccount (account: Account) { private onAccount (account: Account) {
@ -105,16 +105,14 @@ export class AccountsComponent implements OnInit, OnDestroy {
() => { () => {
this.isAccountManageable = this.account.userId && this.account.userId === this.authService.getUser().id this.isAccountManageable = this.account.userId && this.account.userId === this.authService.getUser().id
this.accountFollowerTitle = this.i18n( const followers = this.subscribersDisplayFor(account.followersCount)
'{{followers}} direct account followers', this.accountFollowerTitle = $localize`${followers} direct account followers`
{ followers: this.subscribersDisplayFor(account.followersCount) }
)
// It's not our account, we can report it // It's not our account, we can report it
if (!this.isAccountManageable) { if (!this.isAccountManageable) {
this.prependModerationActions = [ this.prependModerationActions = [
{ {
label: this.i18n('Report account'), label: $localize`Report account`,
handler: () => this.showReportModal() handler: () => this.showReportModal()
} }
] ]

View File

@ -1,9 +1,8 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, ScreenService } from '@app/core' import { AuthService, ScreenService } from '@app/core'
import { ListOverflowItem } from '@app/shared/shared-main' import { ListOverflowItem } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserRight } from '@shared/models'
import { TopMenuDropdownParam } from '@app/shared/shared-main/misc/top-menu-dropdown.component' import { TopMenuDropdownParam } from '@app/shared/shared-main/misc/top-menu-dropdown.component'
import { UserRight } from '@shared/models'
@Component({ @Component({
templateUrl: './admin.component.html', templateUrl: './admin.component.html',
@ -15,8 +14,7 @@ export class AdminComponent implements OnInit {
constructor ( constructor (
private auth: AuthService, private auth: AuthService,
private screen: ScreenService, private screen: ScreenService
private i18n: I18n
) { } ) { }
get isBroadcastMessageDisplayed () { get isBroadcastMessageDisplayed () {
@ -25,20 +23,20 @@ export class AdminComponent implements OnInit {
ngOnInit () { ngOnInit () {
const federationItems: TopMenuDropdownParam = { const federationItems: TopMenuDropdownParam = {
label: this.i18n('Federation'), label: $localize`Federation`,
children: [ children: [
{ {
label: this.i18n('Instances you follow'), label: $localize`Instances you follow`,
routerLink: '/admin/follows/following-list', routerLink: '/admin/follows/following-list',
iconName: 'following' iconName: 'following'
}, },
{ {
label: this.i18n('Instances following you'), label: $localize`Instances following you`,
routerLink: '/admin/follows/followers-list', routerLink: '/admin/follows/followers-list',
iconName: 'follower' iconName: 'follower'
}, },
{ {
label: this.i18n('Video redundancies'), label: $localize`Video redundancies`,
routerLink: '/admin/follows/video-redundancies-list', routerLink: '/admin/follows/video-redundancies-list',
iconName: 'videos' iconName: 'videos'
} }
@ -46,56 +44,56 @@ export class AdminComponent implements OnInit {
} }
const moderationItems: TopMenuDropdownParam = { const moderationItems: TopMenuDropdownParam = {
label: this.i18n('Moderation'), label: $localize`Moderation`,
children: [] children: []
} }
if (this.hasAbusesRight()) { if (this.hasAbusesRight()) {
moderationItems.children.push({ moderationItems.children.push({
label: this.i18n('Reports'), label: $localize`Reports`,
routerLink: '/admin/moderation/abuses/list', routerLink: '/admin/moderation/abuses/list',
iconName: 'flag' iconName: 'flag'
}) })
} }
if (this.hasVideoBlocklistRight()) { if (this.hasVideoBlocklistRight()) {
moderationItems.children.push({ moderationItems.children.push({
label: this.i18n('Video blocks'), label: $localize`Video blocks`,
routerLink: '/admin/moderation/video-blocks/list', routerLink: '/admin/moderation/video-blocks/list',
iconName: 'cross' iconName: 'cross'
}) })
} }
if (this.hasAccountsBlocklistRight()) { if (this.hasAccountsBlocklistRight()) {
moderationItems.children.push({ moderationItems.children.push({
label: this.i18n('Muted accounts'), label: $localize`Muted accounts`,
routerLink: '/admin/moderation/blocklist/accounts', routerLink: '/admin/moderation/blocklist/accounts',
iconName: 'user-x' iconName: 'user-x'
}) })
} }
if (this.hasServersBlocklistRight()) { if (this.hasServersBlocklistRight()) {
moderationItems.children.push({ moderationItems.children.push({
label: this.i18n('Muted servers'), label: $localize`Muted servers`,
routerLink: '/admin/moderation/blocklist/servers', routerLink: '/admin/moderation/blocklist/servers',
iconName: 'peertube-x' iconName: 'peertube-x'
}) })
} }
if (this.hasUsersRight()) { if (this.hasUsersRight()) {
this.menuEntries.push({ label: this.i18n('Users'), routerLink: '/admin/users' }) this.menuEntries.push({ label: $localize`Users`, routerLink: '/admin/users' })
} }
if (this.hasServerFollowRight()) this.menuEntries.push(federationItems) if (this.hasServerFollowRight()) this.menuEntries.push(federationItems)
if (this.hasAbusesRight() || this.hasVideoBlocklistRight()) this.menuEntries.push(moderationItems) if (this.hasAbusesRight() || this.hasVideoBlocklistRight()) this.menuEntries.push(moderationItems)
if (this.hasConfigRight()) { if (this.hasConfigRight()) {
this.menuEntries.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' }) this.menuEntries.push({ label: $localize`Configuration`, routerLink: '/admin/config' })
} }
if (this.hasPluginsRight()) { if (this.hasPluginsRight()) {
this.menuEntries.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' }) this.menuEntries.push({ label: $localize`Plugins/Themes`, routerLink: '/admin/plugins' })
} }
if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) { if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) {
this.menuEntries.push({ label: this.i18n('System'), routerLink: '/admin/system' }) this.menuEntries.push({ label: $localize`System`, routerLink: '/admin/system' })
} }
} }

View File

@ -12,7 +12,6 @@ import {
UserValidatorsService UserValidatorsService
} from '@app/shared/shared-forms' } from '@app/shared/shared-forms'
import { NgbNav } from '@ng-bootstrap/ng-bootstrap' import { NgbNav } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { CustomConfig, ServerConfig } from '@shared/models' import { CustomConfig, ServerConfig } from '@shared/models'
@Component({ @Component({
@ -42,45 +41,44 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A
private userValidatorsService: UserValidatorsService, private userValidatorsService: UserValidatorsService,
private notifier: Notifier, private notifier: Notifier,
private configService: ConfigService, private configService: ConfigService,
private serverService: ServerService, private serverService: ServerService
private i18n: I18n
) { ) {
super() super()
this.resolutions = [ this.resolutions = [
{ {
id: '0p', id: '0p',
label: this.i18n('Audio-only'), label: $localize`Audio-only`,
description: this.i18n('A <code>.mp4</code> that keeps the original audio track, with no video') description: $localize`A <code>.mp4</code> that keeps the original audio track, with no video`
}, },
{ {
id: '240p', id: '240p',
label: this.i18n('240p') label: $localize`240p`
}, },
{ {
id: '360p', id: '360p',
label: this.i18n('360p') label: $localize`360p`
}, },
{ {
id: '480p', id: '480p',
label: this.i18n('480p') label: $localize`480p`
}, },
{ {
id: '720p', id: '720p',
label: this.i18n('720p') label: $localize`720p`
}, },
{ {
id: '1080p', id: '1080p',
label: this.i18n('1080p') label: $localize`1080p`
}, },
{ {
id: '2160p', id: '2160p',
label: this.i18n('2160p') label: $localize`2160p`
} }
] ]
this.transcodingThreadOptions = [ this.transcodingThreadOptions = [
{ value: 0, label: this.i18n('Auto (via ffmpeg)') }, { value: 0, label: $localize`Auto (via ffmpeg)` },
{ value: 1, label: '1' }, { value: 1, label: '1' },
{ value: 2, label: '2' }, { value: 2, label: '2' },
{ value: 4, label: '4' }, { value: 4, label: '4' },
@ -288,7 +286,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A
this.updateForm() this.updateForm()
this.notifier.success(this.i18n('Configuration updated.')) this.notifier.success($localize`Configuration updated.`)
}, },
err => this.notifier.error(err.message) err => this.notifier.error(err.message)

View File

@ -2,7 +2,6 @@ import { catchError } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http' import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { RestExtractor } from '@app/core' import { RestExtractor } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { CustomConfig } from '@shared/models' import { CustomConfig } from '@shared/models'
import { environment } from '../../../../environments/environment' import { environment } from '../../../../environments/environment'
@ -15,33 +14,32 @@ export class ConfigService {
constructor ( constructor (
private authHttp: HttpClient, private authHttp: HttpClient,
private restExtractor: RestExtractor, private restExtractor: RestExtractor
private i18n: I18n ) {
) {
this.videoQuotaOptions = [ this.videoQuotaOptions = [
{ value: undefined, label: 'Default quota', disabled: true }, { value: undefined, label: 'Default quota', disabled: true },
{ value: -1, label: this.i18n('Unlimited') }, { value: -1, label: $localize`Unlimited` },
{ value: undefined, label: '─────', disabled: true }, { value: undefined, label: '─────', disabled: true },
{ value: 0, label: this.i18n('None - no upload possible') }, { value: 0, label: $localize`None - no upload possible` },
{ value: 100 * 1024 * 1024, label: this.i18n('100MB') }, { value: 100 * 1024 * 1024, label: $localize`100MB` },
{ value: 500 * 1024 * 1024, label: this.i18n('500MB') }, { value: 500 * 1024 * 1024, label: $localize`500MB` },
{ value: 1024 * 1024 * 1024, label: this.i18n('1GB') }, { value: 1024 * 1024 * 1024, label: $localize`1GB` },
{ value: 5 * 1024 * 1024 * 1024, label: this.i18n('5GB') }, { value: 5 * 1024 * 1024 * 1024, label: $localize`5GB` },
{ value: 20 * 1024 * 1024 * 1024, label: this.i18n('20GB') }, { value: 20 * 1024 * 1024 * 1024, label: $localize`20GB` },
{ value: 50 * 1024 * 1024 * 1024, label: this.i18n('50GB') } { value: 50 * 1024 * 1024 * 1024, label: $localize`50GB` }
] ]
this.videoQuotaDailyOptions = [ this.videoQuotaDailyOptions = [
{ value: undefined, label: 'Default daily upload limit', disabled: true }, { value: undefined, label: 'Default daily upload limit', disabled: true },
{ value: -1, label: this.i18n('Unlimited') }, { value: -1, label: $localize`Unlimited` },
{ value: undefined, label: '─────', disabled: true }, { value: undefined, label: '─────', disabled: true },
{ value: 0, label: this.i18n('None - no upload possible') }, { value: 0, label: $localize`None - no upload possible` },
{ value: 10 * 1024 * 1024, label: this.i18n('10MB') }, { value: 10 * 1024 * 1024, label: $localize`10MB` },
{ value: 50 * 1024 * 1024, label: this.i18n('50MB') }, { value: 50 * 1024 * 1024, label: $localize`50MB` },
{ value: 100 * 1024 * 1024, label: this.i18n('100MB') }, { value: 100 * 1024 * 1024, label: $localize`100MB` },
{ value: 500 * 1024 * 1024, label: this.i18n('500MB') }, { value: 500 * 1024 * 1024, label: $localize`500MB` },
{ value: 2 * 1024 * 1024 * 1024, label: this.i18n('2GB') }, { value: 2 * 1024 * 1024 * 1024, label: $localize`2GB` },
{ value: 5 * 1024 * 1024 * 1024, label: this.i18n('5GB') } { value: 5 * 1024 * 1024 * 1024, label: $localize`5GB` }
] ]
} }

View File

@ -2,7 +2,6 @@ import { SortMeta } from 'primeng/api'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { InstanceFollowService } from '@app/shared/shared-instance' import { InstanceFollowService } from '@app/shared/shared-instance'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ActorFollow } from '@shared/models' import { ActorFollow } from '@shared/models'
@Component({ @Component({
@ -19,7 +18,6 @@ export class FollowersListComponent extends RestTable implements OnInit {
constructor ( constructor (
private confirmService: ConfirmService, private confirmService: ConfirmService,
private notifier: Notifier, private notifier: Notifier,
private i18n: I18n,
private followService: InstanceFollowService private followService: InstanceFollowService
) { ) {
super() super()
@ -40,7 +38,7 @@ export class FollowersListComponent extends RestTable implements OnInit {
.subscribe( .subscribe(
() => { () => {
const handle = follow.follower.name + '@' + follow.follower.host const handle = follow.follower.name + '@' + follow.follower.host
this.notifier.success(this.i18n('{{handle}} accepted in instance followers', { handle })) this.notifier.success($localize`${handle} accepted in instance followers`)
}, },
err => { err => {
@ -51,15 +49,15 @@ export class FollowersListComponent extends RestTable implements OnInit {
} }
async rejectFollower (follow: ActorFollow) { async rejectFollower (follow: ActorFollow) {
const message = this.i18n('Do you really want to reject this follower?') const message = $localize`Do you really want to reject this follower?`
const res = await this.confirmService.confirm(message, this.i18n('Reject')) const res = await this.confirmService.confirm(message, $localize`Reject`)
if (res === false) return if (res === false) return
this.followService.rejectFollower(follow) this.followService.rejectFollower(follow)
.subscribe( .subscribe(
() => { () => {
const handle = follow.follower.name + '@' + follow.follower.host const handle = follow.follower.name + '@' + follow.follower.host
this.notifier.success(this.i18n('{{handle}} rejected from instance followers', { handle })) this.notifier.success($localize`${handle} rejected from instance followers`)
this.loadData() this.loadData()
}, },
@ -72,15 +70,15 @@ export class FollowersListComponent extends RestTable implements OnInit {
} }
async deleteFollower (follow: ActorFollow) { async deleteFollower (follow: ActorFollow) {
const message = this.i18n('Do you really want to delete this follower?') const message = $localize`Do you really want to delete this follower?`
const res = await this.confirmService.confirm(message, this.i18n('Delete')) const res = await this.confirmService.confirm(message, $localize`Delete`)
if (res === false) return if (res === false) return
this.followService.removeFollower(follow) this.followService.removeFollower(follow)
.subscribe( .subscribe(
() => { () => {
const handle = follow.follower.name + '@' + follow.follower.host const handle = follow.follower.name + '@' + follow.follower.host
this.notifier.success(this.i18n('{{handle}} removed from instance followers', { handle })) this.notifier.success($localize`${handle} removed from instance followers`)
this.loadData() this.loadData()
}, },

View File

@ -3,7 +3,6 @@ import { Component, OnInit, ViewChild } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { InstanceFollowService } from '@app/shared/shared-instance' import { InstanceFollowService } from '@app/shared/shared-instance'
import { BatchDomainsModalComponent } from '@app/shared/shared-moderation' import { BatchDomainsModalComponent } from '@app/shared/shared-moderation'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ActorFollow } from '@shared/models' import { ActorFollow } from '@shared/models'
@Component({ @Component({
@ -22,9 +21,8 @@ export class FollowingListComponent extends RestTable implements OnInit {
constructor ( constructor (
private notifier: Notifier, private notifier: Notifier,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private followService: InstanceFollowService, private followService: InstanceFollowService
private i18n: I18n ) {
) {
super() super()
} }
@ -47,7 +45,7 @@ export class FollowingListComponent extends RestTable implements OnInit {
async addFollowing (hosts: string[]) { async addFollowing (hosts: string[]) {
this.followService.follow(hosts).subscribe( this.followService.follow(hosts).subscribe(
() => { () => {
this.notifier.success(this.i18n('Follow request(s) sent!')) this.notifier.success($localize`Follow request(s) sent!`)
this.loadData() this.loadData()
}, },
@ -57,14 +55,14 @@ export class FollowingListComponent extends RestTable implements OnInit {
async removeFollowing (follow: ActorFollow) { async removeFollowing (follow: ActorFollow) {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to unfollow {{host}}?', { host: follow.following.host }), $localize`Do you really want to unfollow ${follow.following.host}?`,
this.i18n('Unfollow') $localize`Unfollow`
) )
if (res === false) return if (res === false) return
this.followService.unfollow(follow).subscribe( this.followService.unfollow(follow).subscribe(
() => { () => {
this.notifier.success(this.i18n('You are not following {{host}} anymore.', { host: follow.following.host })) this.notifier.success($localize`You are not following ${follow.following.host} anymore.`)
this.loadData() this.loadData()
}, },

View File

@ -1,7 +1,6 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { Notifier } from '@app/core' import { Notifier } from '@app/core'
import { RedundancyService } from '@app/shared/shared-main' import { RedundancyService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-redundancy-checkbox', selector: 'my-redundancy-checkbox',
@ -14,17 +13,16 @@ export class RedundancyCheckboxComponent {
constructor ( constructor (
private notifier: Notifier, private notifier: Notifier,
private redundancyService: RedundancyService, private redundancyService: RedundancyService
private i18n: I18n ) { }
) { }
updateRedundancyState () { updateRedundancyState () {
this.redundancyService.updateRedundancy(this.host, this.redundancyAllowed) this.redundancyService.updateRedundancy(this.host, this.redundancyAllowed)
.subscribe( .subscribe(
() => { () => {
const stateLabel = this.redundancyAllowed ? this.i18n('enabled') : this.i18n('disabled') const stateLabel = this.redundancyAllowed ? $localize`enabled` : $localize`disabled`
this.notifier.success(this.i18n('Redundancy for {{host}} is {{stateLabel}}', { host: this.host, stateLabel })) this.notifier.success($localize`Redundancy for ${this.host} is ${stateLabel}`)
}, },
err => this.notifier.error(err.message) err => this.notifier.error(err.message)

View File

@ -2,7 +2,6 @@ import { SortMeta } from 'primeng/api'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' import { ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { BytesPipe, RedundancyService } from '@app/shared/shared-main' import { BytesPipe, RedundancyService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models'
import { VideosRedundancyStats } from '@shared/models/server' import { VideosRedundancyStats } from '@shared/models/server'
@ -32,9 +31,8 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
private notifier: Notifier, private notifier: Notifier,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private redundancyService: RedundancyService, private redundancyService: RedundancyService,
private serverService: ServerService, private serverService: ServerService
private i18n: I18n ) {
) {
super() super()
this.bytesPipe = new BytesPipe() this.bytesPipe = new BytesPipe()
@ -100,7 +98,7 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
this.redundanciesGraphsData.push({ this.redundanciesGraphsData.push({
stats, stats,
graphData: { graphData: {
labels: [ this.i18n('Used'), this.i18n('Available') ], labels: [ $localize`Used`, $localize`Available` ],
datasets: [ datasets: [
{ {
data: [ stats.totalUsed, totalSize ], data: [ stats.totalUsed, totalSize ],
@ -139,14 +137,14 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
} }
async removeRedundancy (redundancy: VideoRedundancy) { async removeRedundancy (redundancy: VideoRedundancy) {
const message = this.i18n('Do you really want to remove this video redundancy?') const message = $localize`Do you really want to remove this video redundancy?`
const res = await this.confirmService.confirm(message, this.i18n('Remove redundancy')) const res = await this.confirmService.confirm(message, $localize`Remove redundancy`)
if (res === false) return if (res === false) return
this.redundancyService.removeVideoRedundancies(redundancy) this.redundancyService.removeVideoRedundancies(redundancy)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Video redundancies removed!')) this.notifier.success($localize`Video redundancies removed!`)
this.loadData() this.loadData()
}, },

View File

@ -1,15 +1,14 @@
import { SortMeta } from 'primeng/api' import { SortMeta } from 'primeng/api'
import { filter, switchMap } from 'rxjs/operators' import { filter, switchMap } from 'rxjs/operators'
import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
import { environment } from 'src/environments/environment'
import { AfterViewInit, Component, OnInit } from '@angular/core' import { AfterViewInit, Component, OnInit } from '@angular/core'
import { DomSanitizer } from '@angular/platform-browser'
import { ActivatedRoute, Params, Router } from '@angular/router' import { ActivatedRoute, Params, Router } from '@angular/router'
import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
import { VideoBlockService } from '@app/shared/shared-moderation' import { VideoBlockService } from '@app/shared/shared-moderation'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoBlacklist, VideoBlacklistType } from '@shared/models' import { VideoBlacklist, VideoBlacklistType } from '@shared/models'
import { buildVideoOrPlaylistEmbed, buildVideoLink } from 'src/assets/player/utils'
import { environment } from 'src/environments/environment'
import { DomSanitizer } from '@angular/platform-browser'
@Component({ @Component({
selector: 'my-video-block-list', selector: 'my-video-block-list',
@ -34,26 +33,25 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private videoService: VideoService, private videoService: VideoService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router
private i18n: I18n ) {
) {
super() super()
this.videoBlocklistActions = [ this.videoBlocklistActions = [
[ [
{ {
label: this.i18n('Internal actions'), label: $localize`Internal actions`,
isHeader: true, isHeader: true,
isDisplayed: videoBlock => videoBlock.type === VideoBlacklistType.AUTO_BEFORE_PUBLISHED isDisplayed: videoBlock => videoBlock.type === VideoBlacklistType.AUTO_BEFORE_PUBLISHED
}, },
{ {
label: this.i18n('Switch video block to manual'), label: $localize`Switch video block to manual`,
handler: videoBlock => { handler: videoBlock => {
this.videoBlocklistService.unblockVideo(videoBlock.video.id).pipe( this.videoBlocklistService.unblockVideo(videoBlock.video.id).pipe(
switchMap(_ => this.videoBlocklistService.blockVideo(videoBlock.video.id, undefined, true)) switchMap(_ => this.videoBlocklistService.blockVideo(videoBlock.video.id, undefined, true))
).subscribe( ).subscribe(
() => { () => {
this.notifier.success(this.i18n('Video {{name}} switched to manual block.', { name: videoBlock.video.name })) this.notifier.success($localize`Video ${videoBlock.video.name} switched to manual block.`)
this.loadData() this.loadData()
}, },
@ -65,27 +63,27 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV
], ],
[ [
{ {
label: this.i18n('Actions for the video'), label: $localize`Actions for the video`,
isHeader: true isHeader: true
}, },
{ {
label: this.i18n('Unblock'), label: $localize`Unblock`,
handler: videoBlock => this.unblockVideo(videoBlock) handler: videoBlock => this.unblockVideo(videoBlock)
}, },
{ {
label: this.i18n('Delete'), label: $localize`Delete`,
handler: async videoBlock => { handler: async videoBlock => {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to delete this video?'), $localize`Do you really want to delete this video?`,
this.i18n('Delete') $localize`Delete`
) )
if (res === false) return if (res === false) return
this.videoService.removeVideo(videoBlock.video.id) this.videoService.removeVideo(videoBlock.video.id)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Video deleted.')) this.notifier.success($localize`Video deleted.`)
}, },
err => this.notifier.error(err.message) err => this.notifier.error(err.message)
@ -148,9 +146,9 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV
} }
booleanToText (value: boolean) { booleanToText (value: boolean) {
if (value === true) return this.i18n('yes') if (value === true) return $localize`yes`
return this.i18n('no') return $localize`no`
} }
toHtml (text: string) { toHtml (text: string) {
@ -158,16 +156,14 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV
} }
async unblockVideo (entry: VideoBlacklist) { async unblockVideo (entry: VideoBlacklist) {
const confirmMessage = this.i18n( const confirmMessage = $localize`Do you really want to unblock this video? It will be available again in the videos list.`
'Do you really want to unblock this video? It will be available again in the videos list.'
)
const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblock')) const res = await this.confirmService.confirm(confirmMessage, $localize`Unblock`)
if (res === false) return if (res === false) return
this.videoBlocklistService.unblockVideo(entry.video.id).subscribe( this.videoBlocklistService.unblockVideo(entry.video.id).subscribe(
() => { () => {
this.notifier.success(this.i18n('Video {{name}} unblocked.', { name: entry.video.name })) this.notifier.success($localize`Video ${entry.video.name} unblocked.`)
this.loadData() this.loadData()
}, },

View File

@ -4,7 +4,6 @@ import { ActivatedRoute, Router } from '@angular/router'
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
import { ComponentPagination, ConfirmService, hasMoreItems, Notifier } from '@app/core' import { ComponentPagination, ConfirmService, hasMoreItems, Notifier } from '@app/core'
import { PluginService } from '@app/core/plugins/plugin.service' import { PluginService } from '@app/core/plugins/plugin.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { compareSemVer } from '@shared/core-utils/miscs/miscs' import { compareSemVer } from '@shared/core-utils/miscs/miscs'
import { PeerTubePlugin } from '@shared/models/plugins/peertube-plugin.model' import { PeerTubePlugin } from '@shared/models/plugins/peertube-plugin.model'
import { PluginType } from '@shared/models/plugins/plugin.type' import { PluginType } from '@shared/models/plugins/plugin.type'
@ -37,7 +36,6 @@ export class PluginListInstalledComponent implements OnInit {
onDataSubject = new Subject<any[]>() onDataSubject = new Subject<any[]>()
constructor ( constructor (
private i18n: I18n,
private pluginService: PluginService, private pluginService: PluginService,
private pluginApiService: PluginApiService, private pluginApiService: PluginApiService,
private notifier: Notifier, private notifier: Notifier,
@ -88,10 +86,10 @@ export class PluginListInstalledComponent implements OnInit {
getNoResultMessage () { getNoResultMessage () {
if (this.pluginType === PluginType.PLUGIN) { if (this.pluginType === PluginType.PLUGIN) {
return this.i18n("You don't have plugins installed yet.") return $localize`You don't have plugins installed yet.`
} }
return this.i18n("You don't have themes installed yet.") return $localize`You don't have themes installed yet.`
} }
isUpdateAvailable (plugin: PeerTubePlugin) { isUpdateAvailable (plugin: PeerTubePlugin) {
@ -99,7 +97,7 @@ export class PluginListInstalledComponent implements OnInit {
} }
getUpdateLabel (plugin: PeerTubePlugin) { getUpdateLabel (plugin: PeerTubePlugin) {
return this.i18n('Update to {{version}}', { version: plugin.latestVersion }) return $localize`Update to ${plugin.latestVersion}`
} }
isUpdating (plugin: PeerTubePlugin) { isUpdating (plugin: PeerTubePlugin) {
@ -108,15 +106,15 @@ export class PluginListInstalledComponent implements OnInit {
async uninstall (plugin: PeerTubePlugin) { async uninstall (plugin: PeerTubePlugin) {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to uninstall {{pluginName}}?', { pluginName: plugin.name }), $localize`Do you really want to uninstall ${plugin.name}?`,
this.i18n('Uninstall') $localize`Uninstall`
) )
if (res === false) return if (res === false) return
this.pluginApiService.uninstall(plugin.name, plugin.type) this.pluginApiService.uninstall(plugin.name, plugin.type)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('{{pluginName}} uninstalled.', { pluginName: plugin.name })) this.notifier.success($localize`${plugin.name} uninstalled.`)
this.plugins = this.plugins.filter(p => p.name !== plugin.name) this.plugins = this.plugins.filter(p => p.name !== plugin.name)
this.pagination.totalItems-- this.pagination.totalItems--
@ -138,7 +136,7 @@ export class PluginListInstalledComponent implements OnInit {
res => { res => {
this.updating[updatingKey] = false this.updating[updatingKey] = false
this.notifier.success(this.i18n('{{pluginName}} updated.', { pluginName: plugin.name })) this.notifier.success($localize`${plugin.name} updated.`)
Object.assign(plugin, res) Object.assign(plugin, res)
}, },

View File

@ -3,8 +3,7 @@ import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, ServerService } from '@app/core' import { ComponentPagination, ConfirmService, hasMoreItems, Notifier } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { PeerTubePluginIndex } from '@shared/models/plugins/peertube-plugin-index.model' import { PeerTubePluginIndex } from '@shared/models/plugins/peertube-plugin-index.model'
import { PluginType } from '@shared/models/plugins/plugin.type' import { PluginType } from '@shared/models/plugins/plugin.type'
@ -40,8 +39,6 @@ export class PluginSearchComponent implements OnInit {
private searchSubject = new Subject<string>() private searchSubject = new Subject<string>()
constructor ( constructor (
private server: ServerService,
private i18n: I18n,
private pluginService: PluginApiService, private pluginService: PluginApiService,
private notifier: Notifier, private notifier: Notifier,
private confirmService: ConfirmService, private confirmService: ConfirmService,
@ -100,7 +97,7 @@ export class PluginSearchComponent implements OnInit {
err => { err => {
console.error(err) console.error(err)
const message = this.i18n('The plugin index is not available. Please retry later.') const message = $localize`The plugin index is not available. Please retry later.`
this.notifier.error(message) this.notifier.error(message)
} }
) )
@ -122,8 +119,8 @@ export class PluginSearchComponent implements OnInit {
if (this.installing[plugin.npmName]) return if (this.installing[plugin.npmName]) return
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Please only install plugins or themes you trust, since they can execute any code on your instance.'), $localize`Please only install plugins or themes you trust, since they can execute any code on your instance.`,
this.i18n('Install {{pluginName}}?', { pluginName: plugin.name }) $localize`Install ${plugin.name}?`
) )
if (res === false) return if (res === false) return
@ -135,7 +132,7 @@ export class PluginSearchComponent implements OnInit {
this.installing[plugin.npmName] = false this.installing[plugin.npmName] = false
this.pluginInstalled = true this.pluginInstalled = true
this.notifier.success(this.i18n('{{pluginName}} installed.', { pluginName: plugin.name })) this.notifier.success($localize`${plugin.name} installed.`)
plugin.installed = true plugin.installed = true
}, },

View File

@ -4,7 +4,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { Notifier } from '@app/core' import { Notifier } from '@app/core'
import { BuildFormArgument, FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { BuildFormArgument, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { PeerTubePlugin, RegisterServerSettingOptions } from '@shared/models' import { PeerTubePlugin, RegisterServerSettingOptions } from '@shared/models'
import { PluginApiService } from '../shared/plugin-api.service' import { PluginApiService } from '../shared/plugin-api.service'
@ -22,7 +21,6 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
constructor ( constructor (
protected formValidatorService: FormValidatorService, protected formValidatorService: FormValidatorService,
private i18n: I18n,
private pluginService: PluginApiService, private pluginService: PluginApiService,
private notifier: Notifier, private notifier: Notifier,
private route: ActivatedRoute private route: ActivatedRoute
@ -50,7 +48,7 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
this.pluginService.updatePluginSettings(this.plugin.name, this.plugin.type, settings) this.pluginService.updatePluginSettings(this.plugin.name, this.plugin.type, settings)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Settings updated.')) this.notifier.success($localize`Settings updated.`)
}, },
err => this.notifier.error(err.message) err => this.notifier.error(err.message)

View File

@ -4,7 +4,6 @@ import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { ComponentPagination, RestExtractor, RestService } from '@app/core' import { ComponentPagination, RestExtractor, RestService } from '@app/core'
import { PluginService } from '@app/core/plugins/plugin.service' import { PluginService } from '@app/core/plugins/plugin.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { peertubeTranslate } from '@shared/core-utils/i18n' import { peertubeTranslate } from '@shared/core-utils/i18n'
import { import {
InstallOrUpdatePlugin, InstallOrUpdatePlugin,
@ -25,18 +24,17 @@ export class PluginApiService {
private authHttp: HttpClient, private authHttp: HttpClient,
private restExtractor: RestExtractor, private restExtractor: RestExtractor,
private restService: RestService, private restService: RestService,
private i18n: I18n,
private pluginService: PluginService private pluginService: PluginService
) { } ) { }
getPluginTypeOptions () { getPluginTypeOptions () {
return [ return [
{ {
label: this.i18n('Plugins'), label: $localize`Plugins`,
value: PluginType.PLUGIN value: PluginType.PLUGIN
}, },
{ {
label: this.i18n('Themes'), label: $localize`Themes`,
value: PluginType.THEME value: PluginType.THEME
} }
] ]
@ -44,10 +42,10 @@ export class PluginApiService {
getPluginTypeLabel (type: PluginType) { getPluginTypeLabel (type: PluginType) {
if (type === PluginType.PLUGIN) { if (type === PluginType.PLUGIN) {
return this.i18n('plugin') return $localize`plugin`
} }
return this.i18n('theme') return $localize`theme`
} }
getPlugins ( getPlugins (

View File

@ -2,7 +2,6 @@ import { SortMeta } from 'primeng/api'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { Notifier, RestPagination, RestTable } from '@app/core' import { Notifier, RestPagination, RestTable } from '@app/core'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Job, JobState, JobType } from '@shared/models' import { Job, JobState, JobType } from '@shared/models'
import { JobStateClient } from '../../../../types/job-state-client.type' import { JobStateClient } from '../../../../types/job-state-client.type'
import { JobTypeClient } from '../../../../types/job-type-client.type' import { JobTypeClient } from '../../../../types/job-type-client.type'
@ -43,9 +42,8 @@ export class JobsComponent extends RestTable implements OnInit {
constructor ( constructor (
private notifier: Notifier, private notifier: Notifier,
private jobsService: JobService, private jobsService: JobService
private i18n: I18n ) {
) {
super() super()
} }

View File

@ -1,6 +1,5 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { Notifier } from '@app/core' import { Notifier } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { LogLevel } from '@shared/models' import { LogLevel } from '@shared/models'
import { LogRow } from './log-row.model' import { LogRow } from './log-row.model'
import { LogsService } from './logs.service' import { LogsService } from './logs.service'
@ -25,9 +24,8 @@ export class LogsComponent implements OnInit {
constructor ( constructor (
private logsService: LogsService, private logsService: LogsService,
private notifier: Notifier, private notifier: Notifier
private i18n: I18n ) { }
) { }
ngOnInit (): void { ngOnInit (): void {
this.buildTimeChoices() this.buildTimeChoices()
@ -78,15 +76,15 @@ export class LogsComponent implements OnInit {
this.timeChoices = [ this.timeChoices = [
{ {
id: lastWeek.toISOString(), id: lastWeek.toISOString(),
label: this.i18n('Last week') label: $localize`Last week`
}, },
{ {
id: lastDay.toISOString(), id: lastDay.toISOString(),
label: this.i18n('Last day') label: $localize`Last day`
}, },
{ {
id: lastHour.toISOString(), id: lastHour.toISOString(),
label: this.i18n('Last hour') label: $localize`Last hour`
} }
] ]
@ -97,19 +95,19 @@ export class LogsComponent implements OnInit {
this.levelChoices = [ this.levelChoices = [
{ {
id: 'debug', id: 'debug',
label: this.i18n('Debug') label: $localize`Debug`
}, },
{ {
id: 'info', id: 'info',
label: this.i18n('Info') label: $localize`Info`
}, },
{ {
id: 'warn', id: 'warn',
label: this.i18n('Warning') label: $localize`Warning`
}, },
{ {
id: 'error', id: 'error',
label: this.i18n('Error') label: $localize`Error`
} }
] ]
@ -120,11 +118,11 @@ export class LogsComponent implements OnInit {
this.logTypeChoices = [ this.logTypeChoices = [
{ {
id: 'standard', id: 'standard',
label: this.i18n('Standard logs') label: $localize`Standard logs`
}, },
{ {
id: 'audit', id: 'audit',
label: this.i18n('Audit logs') label: $localize`Audit logs`
} }
] ]

View File

@ -3,7 +3,6 @@ import { ActivatedRoute, Router } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service' import { ConfigService } from '@app/+admin/config/shared/config.service'
import { AuthService, Notifier, ScreenService, ServerService, UserService } from '@app/core' import { AuthService, Notifier, ScreenService, ServerService, UserService } from '@app/core'
import { FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserCreate, UserRole } from '@shared/models' import { UserCreate, UserRole } from '@shared/models'
import { UserEdit } from './user-edit' import { UserEdit } from './user-edit'
@ -25,9 +24,8 @@ export class UserCreateComponent extends UserEdit implements OnInit {
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService
private i18n: I18n ) {
) {
super() super()
this.buildQuotaOptions() this.buildQuotaOptions()
@ -67,7 +65,7 @@ export class UserCreateComponent extends UserEdit implements OnInit {
this.userService.addUser(userCreate).subscribe( this.userService.addUser(userCreate).subscribe(
() => { () => {
this.notifier.success(this.i18n('User {{username}} created.', { username: userCreate.username })) this.notifier.success($localize`User ${userCreate.username} created.`)
this.router.navigate([ '/admin/users/list' ]) this.router.navigate([ '/admin/users/list' ])
}, },
@ -85,6 +83,6 @@ export class UserCreateComponent extends UserEdit implements OnInit {
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Create user') return $localize`Create user`
} }
} }

View File

@ -1,7 +1,6 @@
import { Component, Input, OnInit } from '@angular/core' import { Component, Input, OnInit } from '@angular/core'
import { Notifier, UserService } from '@app/core' import { Notifier, UserService } from '@app/core'
import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserUpdate } from '@shared/models' import { UserUpdate } from '@shared/models'
@Component({ @Component({
@ -20,9 +19,8 @@ export class UserPasswordComponent extends FormReactive implements OnInit {
protected formValidatorService: FormValidatorService, protected formValidatorService: FormValidatorService,
private userValidatorsService: UserValidatorsService, private userValidatorsService: UserValidatorsService,
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService
private i18n: I18n ) {
) {
super() super()
} }
@ -39,9 +37,7 @@ export class UserPasswordComponent extends FormReactive implements OnInit {
this.userService.updateUser(this.userId, userUpdate).subscribe( this.userService.updateUser(this.userId, userUpdate).subscribe(
() => { () => {
this.notifier.success( this.notifier.success($localize`Password changed for user ${this.username}.`)
this.i18n('Password changed for user {{username}}.', { username: this.username })
)
}, },
err => this.error = err.message err => this.error = err.message
@ -53,6 +49,6 @@ export class UserPasswordComponent extends FormReactive implements OnInit {
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Update user password') return $localize`Update user password`
} }
} }

View File

@ -4,7 +4,6 @@ import { ActivatedRoute, Router } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service' import { ConfigService } from '@app/+admin/config/shared/config.service'
import { AuthService, Notifier, ScreenService, ServerService, User, UserService } from '@app/core' import { AuthService, Notifier, ScreenService, ServerService, User, UserService } from '@app/core'
import { FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { User as UserType, UserAdminFlag, UserRole, UserUpdate } from '@shared/models' import { User as UserType, UserAdminFlag, UserRole, UserUpdate } from '@shared/models'
import { UserEdit } from './user-edit' import { UserEdit } from './user-edit'
@ -28,9 +27,8 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService
private i18n: I18n ) {
) {
super() super()
this.buildQuotaOptions() this.buildQuotaOptions()
@ -79,7 +77,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
this.userService.updateUser(this.user.id, userUpdate).subscribe( this.userService.updateUser(this.user.id, userUpdate).subscribe(
() => { () => {
this.notifier.success(this.i18n('User {{username}} updated.', { username: this.user.username })) this.notifier.success($localize`User ${this.user.username} updated.`)
this.router.navigate([ '/admin/users/list' ]) this.router.navigate([ '/admin/users/list' ])
}, },
@ -96,15 +94,13 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Update user') return $localize`Update user`
} }
resetPassword () { resetPassword () {
this.userService.askResetPassword(this.user.email).subscribe( this.userService.askResetPassword(this.user.email).subscribe(
() => { () => {
this.notifier.success( this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`)
this.i18n('An email asking for password reset has been sent to {{username}}.', { username: this.user.username })
)
}, },
err => this.error = err.message err => this.error = err.message

View File

@ -1,11 +1,10 @@
import { SortMeta } from 'primeng/api' import { SortMeta } from 'primeng/api'
import { Component, OnInit, ViewChild } from '@angular/core' import { Component, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Params, Router } from '@angular/router'
import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService, UserService } from '@app/core' import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService, UserService } from '@app/core'
import { Actor, DropdownAction } from '@app/shared/shared-main' import { Actor, DropdownAction } from '@app/shared/shared-main'
import { UserBanModalComponent } from '@app/shared/shared-moderation' import { UserBanModalComponent } from '@app/shared/shared-moderation'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig, User, UserRole } from '@shared/models' import { ServerConfig, User, UserRole } from '@shared/models'
import { Params, Router, ActivatedRoute } from '@angular/router'
type UserForList = User & { type UserForList = User & {
rawVideoQuota: number rawVideoQuota: number
@ -42,9 +41,8 @@ export class UserListComponent extends RestTable implements OnInit {
private userService: UserService, private userService: UserService,
private auth: AuthService, private auth: AuthService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router
private i18n: I18n ) {
) {
super() super()
} }
@ -82,26 +80,26 @@ export class UserListComponent extends RestTable implements OnInit {
this.bulkUserActions = [ this.bulkUserActions = [
[ [
{ {
label: this.i18n('Delete'), label: $localize`Delete`,
description: this.i18n('Videos will be deleted, comments will be tombstoned.'), description: $localize`Videos will be deleted, comments will be tombstoned.`,
handler: users => this.removeUsers(users), handler: users => this.removeUsers(users),
isDisplayed: users => users.every(u => this.authUser.canManage(u)) isDisplayed: users => users.every(u => this.authUser.canManage(u))
}, },
{ {
label: this.i18n('Ban'), label: $localize`Ban`,
description: this.i18n('User won\'t be able to login anymore, but videos and comments will be kept as is.'), description: $localize`User won't be able to login anymore, but videos and comments will be kept as is.`,
handler: users => this.openBanUserModal(users), handler: users => this.openBanUserModal(users),
isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === false) isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === false)
}, },
{ {
label: this.i18n('Unban'), label: $localize`Unban`,
handler: users => this.unbanUsers(users), handler: users => this.unbanUsers(users),
isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === true) isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === true)
} }
], ],
[ [
{ {
label: this.i18n('Set Email as Verified'), label: $localize`Set Email as Verified`,
handler: users => this.setEmailsAsVerified(users), handler: users => this.setEmailsAsVerified(users),
isDisplayed: users => { isDisplayed: users => {
return this.requiresEmailVerification && return this.requiresEmailVerification &&
@ -160,7 +158,7 @@ export class UserListComponent extends RestTable implements OnInit {
openBanUserModal (users: User[]) { openBanUserModal (users: User[]) {
for (const user of users) { for (const user of users) {
if (user.username === 'root') { if (user.username === 'root') {
this.notifier.error(this.i18n('You cannot ban root.')) this.notifier.error($localize`You cannot ban root.`)
return return
} }
} }
@ -197,17 +195,13 @@ export class UserListComponent extends RestTable implements OnInit {
} }
async unbanUsers (users: User[]) { async unbanUsers (users: User[]) {
const message = this.i18n('Do you really want to unban {{num}} users?', { num: users.length }) const res = await this.confirmService.confirm($localize`Do you really want to unban ${users.length} users?`, $localize`Unban`)
const res = await this.confirmService.confirm(message, this.i18n('Unban'))
if (res === false) return if (res === false) return
this.userService.unbanUsers(users) this.userService.unbanUsers(users)
.subscribe( .subscribe(
() => { () => {
const message = this.i18n('{{num}} users unbanned.', { num: users.length }) this.notifier.success($localize`${users.length} users unbanned.`)
this.notifier.success(message)
this.loadData() this.loadData()
}, },
@ -218,18 +212,18 @@ export class UserListComponent extends RestTable implements OnInit {
async removeUsers (users: User[]) { async removeUsers (users: User[]) {
for (const user of users) { for (const user of users) {
if (user.username === 'root') { if (user.username === 'root') {
this.notifier.error(this.i18n('You cannot delete root.')) this.notifier.error($localize`You cannot delete root.`)
return return
} }
} }
const message = this.i18n('If you remove these users, you will not be able to create others with the same username!') const message = $localize`If you remove these users, you will not be able to create others with the same username!`
const res = await this.confirmService.confirm(message, this.i18n('Delete')) const res = await this.confirmService.confirm(message, $localize`Delete`)
if (res === false) return if (res === false) return
this.userService.removeUser(users).subscribe( this.userService.removeUser(users).subscribe(
() => { () => {
this.notifier.success(this.i18n('{{num}} users deleted.', { num: users.length })) this.notifier.success($localize`${users.length} users deleted.`)
this.loadData() this.loadData()
}, },
@ -240,7 +234,7 @@ export class UserListComponent extends RestTable implements OnInit {
async setEmailsAsVerified (users: User[]) { async setEmailsAsVerified (users: User[]) {
this.userService.updateUsers(users, { emailVerified: true }).subscribe( this.userService.updateUsers(users, { emailVerified: true }).subscribe(
() => { () => {
this.notifier.success(this.i18n('{{num}} users email set as verified.', { num: users.length })) this.notifier.success($localize`${users.length} users email set as verified.`)
this.loadData() this.loadData()
}, },

View File

@ -5,7 +5,6 @@ import { AuthService, Notifier, RedirectService, UserService } from '@app/core'
import { HooksService } from '@app/core/plugins/hooks.service' import { HooksService } from '@app/core/plugins/hooks.service'
import { FormReactive, FormValidatorService, LoginValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, LoginValidatorsService } from '@app/shared/shared-forms'
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { RegisteredExternalAuthConfig, ServerConfig } from '@shared/models' import { RegisteredExternalAuthConfig, ServerConfig } from '@shared/models'
@Component({ @Component({
@ -37,9 +36,8 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
private userService: UserService, private userService: UserService,
private redirectService: RedirectService, private redirectService: RedirectService,
private notifier: Notifier, private notifier: Notifier,
private hooks: HooksService, private hooks: HooksService
private i18n: I18n ) {
) {
super() super()
} }
@ -105,10 +103,9 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
this.userService.askResetPassword(this.forgotPasswordEmail) this.userService.askResetPassword(this.forgotPasswordEmail)
.subscribe( .subscribe(
() => { () => {
const message = this.i18n( const message = $localize`An email with the reset password instructions will be sent to ${this.forgotPasswordEmail}.
'An email with the reset password instructions will be sent to {{email}}. The link will expire within 1 hour.', The link will expire within 1 hour.`
{ email: this.forgotPasswordEmail }
)
this.notifier.success(message) this.notifier.success(message)
this.hideForgotPasswordModal() this.hideForgotPasswordModal()
}, },
@ -140,8 +137,8 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
} }
private handleError (err: any) { private handleError (err: any) {
if (err.message.indexOf('credentials are invalid') !== -1) this.error = this.i18n('Incorrect username or password.') if (err.message.indexOf('credentials are invalid') !== -1) this.error = $localize`Incorrect username or password.`
else if (err.message.indexOf('blocked') !== -1) this.error = this.i18n('Your account is blocked.') else if (err.message.indexOf('blocked') !== -1) this.error = $localize`Your account is blocked.`
else this.error = err.message else this.error = err.message
} }
} }

View File

@ -3,7 +3,6 @@ import { Router } from '@angular/router'
import { AuthService, Notifier } from '@app/core' import { AuthService, Notifier } from '@app/core'
import { FormValidatorService, VideoChannelValidatorsService } from '@app/shared/shared-forms' import { FormValidatorService, VideoChannelValidatorsService } from '@app/shared/shared-forms'
import { VideoChannelService } from '@app/shared/shared-main' import { VideoChannelService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoChannelCreate } from '@shared/models' import { VideoChannelCreate } from '@shared/models'
import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
@ -21,9 +20,8 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
private videoChannelValidatorsService: VideoChannelValidatorsService, private videoChannelValidatorsService: VideoChannelValidatorsService,
private notifier: Notifier, private notifier: Notifier,
private router: Router, private router: Router,
private videoChannelService: VideoChannelService, private videoChannelService: VideoChannelService
private i18n: I18n ) {
) {
super() super()
} }
@ -55,15 +53,13 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
() => { () => {
this.authService.refreshUserInformation() this.authService.refreshUserInformation()
this.notifier.success( this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`)
this.i18n('Video channel {{videoChannelName}} created.', { videoChannelName: videoChannelCreate.displayName })
)
this.router.navigate([ '/my-account', 'video-channels' ]) this.router.navigate([ '/my-account', 'video-channels' ])
}, },
err => { err => {
if (err.status === 409) { if (err.status === 409) {
this.error = this.i18n('This name already exists on this instance.') this.error = $localize`This name already exists on this instance.`
return return
} }
@ -77,6 +73,6 @@ export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelE
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Create') return $localize`Create`
} }
} }

View File

@ -4,7 +4,6 @@ import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, Notifier, ServerService } from '@app/core' import { AuthService, Notifier, ServerService } from '@app/core'
import { FormValidatorService, VideoChannelValidatorsService } from '@app/shared/shared-forms' import { FormValidatorService, VideoChannelValidatorsService } from '@app/shared/shared-forms'
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig, VideoChannelUpdate } from '@shared/models' import { ServerConfig, VideoChannelUpdate } from '@shared/models'
import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
@ -29,7 +28,6 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private videoChannelService: VideoChannelService, private videoChannelService: VideoChannelService,
private i18n: I18n,
private serverService: ServerService private serverService: ServerService
) { ) {
super() super()
@ -87,9 +85,7 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
() => { () => {
this.authService.refreshUserInformation() this.authService.refreshUserInformation()
this.notifier.success( this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`)
this.i18n('Video channel {{videoChannelName}} updated.', { videoChannelName: videoChannelUpdate.displayName })
)
this.router.navigate([ '/my-account', 'video-channels' ]) this.router.navigate([ '/my-account', 'video-channels' ])
}, },
@ -102,7 +98,7 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
this.videoChannelService.changeVideoChannelAvatar(this.videoChannelToUpdate.name, formData) this.videoChannelService.changeVideoChannelAvatar(this.videoChannelToUpdate.name, formData)
.subscribe( .subscribe(
data => { data => {
this.notifier.success(this.i18n('Avatar changed.')) this.notifier.success($localize`Avatar changed.`)
this.videoChannelToUpdate.updateAvatar(data.avatar) this.videoChannelToUpdate.updateAvatar(data.avatar)
}, },
@ -124,7 +120,7 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Update') return $localize`Update`
} }
isBulkUpdateVideosDisplayed () { isBulkUpdateVideosDisplayed () {

View File

@ -1,11 +1,10 @@
import { ChartData } from 'chart.js' import { ChartData } from 'chart.js'
import { max, maxBy, min, minBy } from 'lodash-es' import { max, maxBy, min, minBy } from 'lodash-es'
import { flatMap, debounceTime } from 'rxjs/operators' import { Subject } from 'rxjs'
import { debounceTime, mergeMap } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, ConfirmService, Notifier, ScreenService, User } from '@app/core' import { AuthService, ConfirmService, Notifier, ScreenService, User } from '@app/core'
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Subject } from 'rxjs'
@Component({ @Component({
selector: 'my-account-video-channels', selector: 'my-account-video-channels',
@ -30,9 +29,8 @@ export class MyAccountVideoChannelsComponent implements OnInit {
private notifier: Notifier, private notifier: Notifier,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private videoChannelService: VideoChannelService, private videoChannelService: VideoChannelService,
private screenService: ScreenService, private screenService: ScreenService
private i18n: I18n ) {}
) {}
ngOnInit () { ngOnInit () {
this.user = this.authService.getUser() this.user = this.authService.getUser()
@ -110,17 +108,13 @@ export class MyAccountVideoChannelsComponent implements OnInit {
async deleteVideoChannel (videoChannel: VideoChannel) { async deleteVideoChannel (videoChannel: VideoChannel) {
const res = await this.confirmService.confirmWithInput( const res = await this.confirmService.confirmWithInput(
this.i18n( $localize`Do you really want to delete ${videoChannel.displayName}?
// tslint:disable It will delete ${videoChannel.videosCount} videos uploaded in this channel, and you will not be able to create another
'Do you really want to delete {{channelDisplayName}}? It will delete {{videosCount}} videos uploaded in this channel, and you will not be able to create another channel with the same name ({{channelName}})!', channel with the same name (${videoChannel.name})!`,
{ channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name }
), $localize`Please type the display name of the video channel (${videoChannel.displayName}) to confirm`,
this.i18n(
'Please type the display name of the video channel ({{displayName}}) to confirm', $localize`Delete`
{ displayName: videoChannel.displayName }
),
videoChannel.displayName,
this.i18n('Delete')
) )
if (res === false) return if (res === false) return
@ -128,9 +122,7 @@ export class MyAccountVideoChannelsComponent implements OnInit {
.subscribe( .subscribe(
() => { () => {
this.loadVideoChannels() this.loadVideoChannels()
this.notifier.success( this.notifier.success($localize`Video channel ${videoChannel.displayName} deleted.`)
this.i18n('Video channel {{videoChannelName}} deleted.', { videoChannelName: videoChannel.displayName })
)
}, },
error => this.notifier.error(error.message) error => this.notifier.error(error.message)
@ -139,7 +131,7 @@ export class MyAccountVideoChannelsComponent implements OnInit {
private loadVideoChannels () { private loadVideoChannels () {
this.authService.userInformationLoaded this.authService.userInformationLoaded
.pipe(flatMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true, this.channelsSearch))) .pipe(mergeMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true, this.channelsSearch)))
.subscribe(res => { .subscribe(res => {
this.videoChannels = res.data this.videoChannels = res.data
this.totalItems = res.total this.totalItems = res.total
@ -149,10 +141,10 @@ export class MyAccountVideoChannelsComponent implements OnInit {
labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()), labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()),
datasets: [ datasets: [
{ {
label: this.i18n('Views for the day'), label: $localize`Views for the day`,
data: v.viewsPerDay.map(day => day.views), data: v.viewsPerDay.map(day => day.views),
fill: false, fill: false,
borderColor: "#c6c6c6" borderColor: '#c6c6c6'
} }
] ]
} as ChartData)) } as ChartData))
@ -160,13 +152,15 @@ export class MyAccountVideoChannelsComponent implements OnInit {
// chart options that depend on chart data: // chart options that depend on chart data:
// we don't want to skew values and have min at 0, so we define what the floor/ceiling is here // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here
this.videoChannelsMinimumDailyViews = min( this.videoChannelsMinimumDailyViews = min(
this.videoChannels.map(v => minBy( // compute local minimum daily views for each channel, by their "views" attribute // compute local minimum daily views for each channel, by their "views" attribute
this.videoChannels.map(v => minBy(
v.viewsPerDay, v.viewsPerDay,
day => day.views day => day.views
).views) // the object returned is a ViewPerDate, so we still need to get the views attribute ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
) )
this.videoChannelsMaximumDailyViews = max( this.videoChannelsMaximumDailyViews = max(
this.videoChannels.map(v => maxBy( // compute local maximum daily views for each channel, by their "views" attribute // compute local maximum daily views for each channel, by their "views" attribute
this.videoChannels.map(v => maxBy(
v.viewsPerDay, v.viewsPerDay,
day => day.views day => day.views
).views) // the object returned is a ViewPerDate, so we still need to get the views attribute ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute

View File

@ -13,7 +13,6 @@ import {
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { UserHistoryService } from '@app/shared/shared-main' import { UserHistoryService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-account-history', selector: 'my-account-history',
@ -30,7 +29,6 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
videosHistoryEnabled: boolean videosHistoryEnabled: boolean
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -44,7 +42,7 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
) { ) {
super() super()
this.titlePage = this.i18n('My videos history') this.titlePage = $localize`My videos history`
} }
ngOnInit () { ngOnInit () {
@ -72,8 +70,8 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
.subscribe( .subscribe(
() => { () => {
const message = this.videosHistoryEnabled === true ? const message = this.videosHistoryEnabled === true ?
this.i18n('Videos history is enabled') : $localize`Videos history is enabled` :
this.i18n('Videos history is disabled') $localize`Videos history is disabled`
this.notifier.success(message) this.notifier.success(message)
@ -85,8 +83,8 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
} }
async deleteHistory () { async deleteHistory () {
const title = this.i18n('Delete videos history') const title = $localize`Delete videos history`
const message = this.i18n('Are you sure you want to delete all your videos history?') const message = $localize`Are you sure you want to delete all your videos history?`
const res = await this.confirmService.confirm(message, title) const res = await this.confirmService.confirm(message, title)
if (res !== true) return if (res !== true) return
@ -94,7 +92,7 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
this.userHistoryService.deleteUserVideosHistory() this.userHistoryService.deleteUserVideosHistory()
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Videos history deleted')) this.notifier.success($localize`Videos history deleted`)
this.reloadVideos() this.reloadVideos()
}, },

View File

@ -3,7 +3,6 @@ import { AuthService, Notifier } from '@app/core'
import { FormReactive, FormValidatorService, VideoAcceptOwnershipValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, VideoAcceptOwnershipValidatorsService } from '@app/shared/shared-forms'
import { VideoChannelService, VideoOwnershipService } from '@app/shared/shared-main' import { VideoChannelService, VideoOwnershipService } from '@app/shared/shared-main'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoChangeOwnership, VideoChannel } from '@shared/models' import { VideoChangeOwnership, VideoChannel } from '@shared/models'
@Component({ @Component({
@ -29,9 +28,8 @@ export class MyAccountAcceptOwnershipComponent extends FormReactive implements O
private notifier: Notifier, private notifier: Notifier,
private authService: AuthService, private authService: AuthService,
private videoChannelService: VideoChannelService, private videoChannelService: VideoChannelService,
private modalService: NgbModal, private modalService: NgbModal
private i18n: I18n ) {
) {
super() super()
} }
@ -63,7 +61,7 @@ export class MyAccountAcceptOwnershipComponent extends FormReactive implements O
.acceptOwnership(videoChangeOwnership.id, { channelId: channel }) .acceptOwnership(videoChangeOwnership.id, { channelId: channel })
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Ownership accepted')) this.notifier.success($localize`Ownership accepted`)
if (this.accepted) this.accepted.emit() if (this.accepted) this.accepted.emit()
this.videoChangeOwnership = undefined this.videoChangeOwnership = undefined
}, },

View File

@ -3,7 +3,6 @@ import { tap } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, ServerService, UserService } from '@app/core' import { AuthService, ServerService, UserService } from '@app/core'
import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { User } from '@shared/models' import { User } from '@shared/models'
@Component({ @Component({
@ -21,9 +20,8 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
private userValidatorsService: UserValidatorsService, private userValidatorsService: UserValidatorsService,
private authService: AuthService, private authService: AuthService,
private userService: UserService, private userService: UserService,
private serverService: ServerService, private serverService: ServerService
private i18n: I18n ) {
) {
super() super()
} }
@ -52,15 +50,15 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
this.form.reset() this.form.reset()
if (config.signup.requiresEmailVerification) { if (config.signup.requiresEmailVerification) {
this.success = this.i18n('Please check your emails to verify your new email.') this.success = $localize`Please check your emails to verify your new email.`
} else { } else {
this.success = this.i18n('Email updated.') this.success = $localize`Email updated.`
} }
}, },
err => { err => {
if (err.status === 401) { if (err.status === 401) {
this.error = this.i18n('You current password is invalid.') this.error = $localize`You current password is invalid.`
return return
} }

View File

@ -2,7 +2,6 @@ import { filter } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, Notifier, UserService } from '@app/core' import { AuthService, Notifier, UserService } from '@app/core'
import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { User } from '@shared/models' import { User } from '@shared/models'
@Component({ @Component({
@ -19,9 +18,8 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
private userValidatorsService: UserValidatorsService, private userValidatorsService: UserValidatorsService,
private notifier: Notifier, private notifier: Notifier,
private authService: AuthService, private authService: AuthService,
private userService: UserService, private userService: UserService
private i18n: I18n ) {
) {
super() super()
} }
@ -47,7 +45,7 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
this.userService.changePassword(currentPassword, newPassword).subscribe( this.userService.changePassword(currentPassword, newPassword).subscribe(
() => { () => {
this.notifier.success(this.i18n('Password updated.')) this.notifier.success($localize`Password updated.`)
this.form.reset() this.form.reset()
this.error = null this.error = null
@ -55,7 +53,7 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
err => { err => {
if (err.status === 401) { if (err.status === 401) {
this.error = this.i18n('You current password is invalid.') this.error = $localize`You current password is invalid.`
return return
} }

View File

@ -1,6 +1,5 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { AuthService, ConfirmService, Notifier, RedirectService, User, UserService } from '@app/core' import { AuthService, ConfirmService, Notifier, RedirectService, User, UserService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-account-danger-zone', selector: 'my-account-danger-zone',
@ -15,23 +14,22 @@ export class MyAccountDangerZoneComponent {
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private redirectService: RedirectService, private redirectService: RedirectService
private i18n: I18n ) { }
) { }
async deleteMe () { async deleteMe () {
const res = await this.confirmService.confirmWithInput( const res = await this.confirmService.confirmWithInput(
this.i18n('Are you sure you want to delete your account? This will delete all your data, including channels, videos and comments. Content cached by other servers and other third-parties might make longer to be deleted.'), $localize`Are you sure you want to delete your account? This will delete all your data, including channels, videos and comments. Content cached by other servers and other third-parties might make longer to be deleted.`,
this.i18n('Type your username to confirm'), $localize`Type your username to confirm`,
this.user.username, this.user.username,
this.i18n('Delete your account'), $localize`Delete your account`,
this.i18n('Delete my account') $localize`Delete my account`
) )
if (res === false) return if (res === false) return
this.userService.deleteMe().subscribe( this.userService.deleteMe().subscribe(
() => { () => {
this.notifier.success(this.i18n('Your account is deleted.')) this.notifier.success($localize`Your account is deleted.`)
this.authService.logout() this.authService.logout()
this.redirectService.redirectToHomepage() this.redirectService.redirectToHomepage()

View File

@ -3,7 +3,6 @@ import { Subject } from 'rxjs'
import { Component, Input, OnInit } from '@angular/core' import { Component, Input, OnInit } from '@angular/core'
import { Notifier, ServerService, User } from '@app/core' import { Notifier, ServerService, User } from '@app/core'
import { UserNotificationService } from '@app/shared/shared-main' import { UserNotificationService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserNotificationSetting, UserNotificationSettingValue, UserRight } from '@shared/models' import { UserNotificationSetting, UserNotificationSettingValue, UserRight } from '@shared/models'
@Component({ @Component({
@ -25,26 +24,25 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
private savePreferences = debounce(this.savePreferencesImpl.bind(this), 500) private savePreferences = debounce(this.savePreferencesImpl.bind(this), 500)
constructor ( constructor (
private i18n: I18n,
private userNotificationService: UserNotificationService, private userNotificationService: UserNotificationService,
private serverService: ServerService, private serverService: ServerService,
private notifier: Notifier private notifier: Notifier
) { ) {
this.labelNotifications = { this.labelNotifications = {
newVideoFromSubscription: this.i18n('New video from your subscriptions'), newVideoFromSubscription: $localize`New video from your subscriptions`,
newCommentOnMyVideo: this.i18n('New comment on your video'), newCommentOnMyVideo: $localize`New comment on your video`,
abuseAsModerator: this.i18n('New abuse'), abuseAsModerator: $localize`New abuse`,
videoAutoBlacklistAsModerator: this.i18n('Video blocked automatically waiting review'), videoAutoBlacklistAsModerator: $localize`Video blocked automatically waiting review`,
blacklistOnMyVideo: this.i18n('One of your video is blocked/unblocked'), blacklistOnMyVideo: $localize`One of your video is blocked/unblocked`,
myVideoPublished: this.i18n('Video published (after transcoding/scheduled update)'), myVideoPublished: $localize`Video published (after transcoding/scheduled update)`,
myVideoImportFinished: this.i18n('Video import finished'), myVideoImportFinished: $localize`Video import finished`,
newUserRegistration: this.i18n('A new user registered on your instance'), newUserRegistration: $localize`A new user registered on your instance`,
newFollow: this.i18n('You or your channel(s) has a new follower'), newFollow: $localize`You or your channel(s) has a new follower`,
commentMention: this.i18n('Someone mentioned you in video comments'), commentMention: $localize`Someone mentioned you in video comments`,
newInstanceFollower: this.i18n('Your instance has a new follower'), newInstanceFollower: $localize`Your instance has a new follower`,
autoInstanceFollowing: this.i18n('Your instance automatically followed another instance'), autoInstanceFollowing: $localize`Your instance automatically followed another instance`,
abuseNewMessage: this.i18n('An abuse report received a new message'), abuseNewMessage: $localize`An abuse report received a new message`,
abuseStateChange: this.i18n('One of your abuse reports has been accepted or rejected by moderators') abuseStateChange: $localize`One of your abuse reports has been accepted or rejected by moderators`
} }
this.notificationSettingKeys = Object.keys(this.labelNotifications) as (keyof UserNotificationSetting)[] this.notificationSettingKeys = Object.keys(this.labelNotifications) as (keyof UserNotificationSetting)[]
@ -91,7 +89,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
this.userNotificationService.updateNotificationSettings(this.user, this.user.notificationSettings) this.userNotificationService.updateNotificationSettings(this.user, this.user.notificationSettings)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Preferences saved'), undefined, 2000) this.notifier.success($localize`Preferences saved`, undefined, 2000)
}, },
err => this.notifier.error(err.message) err => this.notifier.error(err.message)

View File

@ -2,7 +2,6 @@ import { Subject } from 'rxjs'
import { Component, Input, OnInit } from '@angular/core' import { Component, Input, OnInit } from '@angular/core'
import { Notifier, User, UserService } from '@app/core' import { Notifier, User, UserService } from '@app/core'
import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-account-profile', selector: 'my-account-profile',
@ -19,9 +18,8 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
protected formValidatorService: FormValidatorService, protected formValidatorService: FormValidatorService,
private userValidatorsService: UserValidatorsService, private userValidatorsService: UserValidatorsService,
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService
private i18n: I18n ) {
) {
super() super()
} }
@ -50,7 +48,7 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
this.user.account.displayName = displayName this.user.account.displayName = displayName
this.user.account.description = description this.user.account.description = description
this.notifier.success(this.i18n('Profile updated.')) this.notifier.success($localize`Profile updated.`)
}, },
err => this.error = err.message err => this.error = err.message

View File

@ -1,7 +1,6 @@
import { ViewportScroller } from '@angular/common' import { ViewportScroller } from '@angular/common'
import { AfterViewChecked, Component, OnInit } from '@angular/core' import { AfterViewChecked, Component, OnInit } from '@angular/core'
import { AuthService, Notifier, User, UserService } from '@app/core' import { AuthService, Notifier, User, UserService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-account-settings', selector: 'my-account-settings',
@ -17,9 +16,8 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
private viewportScroller: ViewportScroller, private viewportScroller: ViewportScroller,
private userService: UserService, private userService: UserService,
private authService: AuthService, private authService: AuthService,
private notifier: Notifier, private notifier: Notifier
private i18n: I18n ) {}
) {}
get userInformationLoaded () { get userInformationLoaded () {
return this.authService.userInformationLoaded return this.authService.userInformationLoaded
@ -41,7 +39,7 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
this.userService.changeAvatar(formData) this.userService.changeAvatar(formData)
.subscribe( .subscribe(
data => { data => {
this.notifier.success(this.i18n('Avatar changed.')) this.notifier.success($localize`Avatar changed.`)
this.user.updateAccountAvatar(data.avatar) this.user.updateAccountAvatar(data.avatar)
}, },

View File

@ -1,13 +1,12 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { AuthService, Notifier, ServerService } from '@app/core' import { AuthService, Notifier, ServerService } from '@app/core'
import { populateAsyncUserVideoChannels } from '@app/helpers'
import { FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/shared-forms' import { FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/shared-forms'
import { VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model' import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model'
import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model'
import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit' import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit'
import { populateAsyncUserVideoChannels } from '@app/helpers'
@Component({ @Component({
selector: 'my-account-video-playlist-create', selector: 'my-account-video-playlist-create',
@ -24,9 +23,8 @@ export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylis
private notifier: Notifier, private notifier: Notifier,
private router: Router, private router: Router,
private videoPlaylistService: VideoPlaylistService, private videoPlaylistService: VideoPlaylistService,
private serverService: ServerService, private serverService: ServerService
private i18n: I18n ) {
) {
super() super()
} }
@ -70,9 +68,7 @@ export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylis
this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe( this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe(
() => { () => {
this.notifier.success( this.notifier.success($localize`Playlist ${videoPlaylistCreate.displayName} created.`)
this.i18n('Playlist {{playlistName}} created.', { playlistName: videoPlaylistCreate.displayName })
)
this.router.navigate([ '/my-account', 'video-playlists' ]) this.router.navigate([ '/my-account', 'video-playlists' ])
}, },
@ -85,6 +81,6 @@ export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylis
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Create') return $localize`Create`
} }
} }

View File

@ -6,7 +6,6 @@ import { ComponentPagination, ConfirmService, Notifier, ScreenService } from '@a
import { DropdownAction } from '@app/shared/shared-main' import { DropdownAction } from '@app/shared/shared-main'
import { VideoShareComponent } from '@app/shared/shared-share-modal' import { VideoShareComponent } from '@app/shared/shared-share-modal'
import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPlaylistType } from '@shared/models' import { VideoPlaylistType } from '@shared/models'
@Component({ @Component({
@ -35,7 +34,6 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
constructor ( constructor (
private notifier: Notifier, private notifier: Notifier,
private i18n: I18n,
private router: Router, private router: Router,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private route: ActivatedRoute, private route: ActivatedRoute,
@ -47,12 +45,12 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
this.playlistActions = [ this.playlistActions = [
[ [
{ {
label: this.i18n('Update playlist'), label: $localize`Update playlist`,
iconName: 'edit', iconName: 'edit',
linkBuilder: playlist => [ '/my-account', 'video-playlists', 'update', playlist.uuid ] linkBuilder: playlist => [ '/my-account', 'video-playlists', 'update', playlist.uuid ]
}, },
{ {
label: this.i18n('Delete playlist'), label: $localize`Delete playlist`,
iconName: 'delete', iconName: 'delete',
handler: playlist => this.deleteVideoPlaylist(playlist) handler: playlist => this.deleteVideoPlaylist(playlist)
} }
@ -126,11 +124,8 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n( $localize`Do you really want to delete ${videoPlaylist.displayName}?`,
'Do you really want to delete {{playlistDisplayName}}?', $localize`Delete`
{ playlistDisplayName: videoPlaylist.displayName }
),
this.i18n('Delete')
) )
if (res === false) return if (res === false) return
@ -138,10 +133,7 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
.subscribe( .subscribe(
() => { () => {
this.router.navigate([ '/my-account', 'video-playlists' ]) this.router.navigate([ '/my-account', 'video-playlists' ])
this.notifier.success($localize`Playlist ${videoPlaylist.displayName} deleted.`)
this.notifier.success(
this.i18n('Playlist {{playlistDisplayName}} deleted.', { playlistDisplayName: videoPlaylist.displayName })
)
}, },
error => this.notifier.error(error.message) error => this.notifier.error(error.message)

View File

@ -6,7 +6,6 @@ import { AuthService, Notifier, ServerService } from '@app/core'
import { populateAsyncUserVideoChannels } from '@app/helpers' import { populateAsyncUserVideoChannels } from '@app/helpers'
import { FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/shared-forms' import { FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/shared-forms'
import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPlaylistUpdate } from '@shared/models' import { VideoPlaylistUpdate } from '@shared/models'
import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit' import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit'
@ -29,7 +28,6 @@ export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylis
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private videoPlaylistService: VideoPlaylistService, private videoPlaylistService: VideoPlaylistService,
private i18n: I18n,
private serverService: ServerService private serverService: ServerService
) { ) {
super() super()
@ -91,10 +89,7 @@ export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylis
this.videoPlaylistService.updateVideoPlaylist(this.videoPlaylistToUpdate, videoPlaylistUpdate).subscribe( this.videoPlaylistService.updateVideoPlaylist(this.videoPlaylistToUpdate, videoPlaylistUpdate).subscribe(
() => { () => {
this.notifier.success( this.notifier.success($localize`Playlist ${videoPlaylistUpdate.displayName} updated.`)
this.i18n('Playlist {{videoPlaylistName}} updated.', { videoPlaylistName: videoPlaylistUpdate.displayName })
)
this.router.navigate([ '/my-account', 'video-playlists' ]) this.router.navigate([ '/my-account', 'video-playlists' ])
}, },
@ -107,7 +102,7 @@ export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylis
} }
getFormButtonTitle () { getFormButtonTitle () {
return this.i18n('Update') return $localize`Update`
} }
private hydrateFormFromPlaylist () { private hydrateFormFromPlaylist () {

View File

@ -3,7 +3,6 @@ import { debounceTime, mergeMap } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, ComponentPagination, ConfirmService, Notifier, User } from '@app/core' import { AuthService, ComponentPagination, ConfirmService, Notifier, User } from '@app/core'
import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPlaylistType } from '@shared/models' import { VideoPlaylistType } from '@shared/models'
@Component({ @Component({
@ -30,9 +29,8 @@ export class MyAccountVideoPlaylistsComponent implements OnInit {
private authService: AuthService, private authService: AuthService,
private notifier: Notifier, private notifier: Notifier,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private videoPlaylistService: VideoPlaylistService, private videoPlaylistService: VideoPlaylistService
private i18n: I18n ) {}
) {}
ngOnInit () { ngOnInit () {
this.user = this.authService.getUser() this.user = this.authService.getUser()
@ -49,11 +47,8 @@ export class MyAccountVideoPlaylistsComponent implements OnInit {
async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n( $localize`Do you really want to delete ${videoPlaylist.displayName}?`,
'Do you really want to delete {{playlistDisplayName}}?', $localize`Delete`
{ playlistDisplayName: videoPlaylist.displayName }
),
this.i18n('Delete')
) )
if (res === false) return if (res === false) return
@ -63,9 +58,7 @@ export class MyAccountVideoPlaylistsComponent implements OnInit {
this.videoPlaylists = this.videoPlaylists this.videoPlaylists = this.videoPlaylists
.filter(p => p.id !== videoPlaylist.id) .filter(p => p.id !== videoPlaylist.id)
this.notifier.success( this.notifier.success($localize`Playlist ${videoPlaylist.displayName}} deleted.`)
this.i18n('Playlist {{playlistDisplayName}} deleted.', { playlistDisplayName: videoPlaylist.displayName })
)
}, },
error => this.notifier.error(error.message) error => this.notifier.error(error.message)

View File

@ -7,7 +7,6 @@ import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { Video, VideoService } from '@app/shared/shared-main' import { Video, VideoService } from '@app/shared/shared-main'
import { MiniatureDisplayOptions, OwnerDisplayType, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' import { MiniatureDisplayOptions, OwnerDisplayType, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@shared/models'
import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component' import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component'
@ -50,11 +49,10 @@ export class MyAccountVideosComponent implements OnInit, DisableForReuseHook {
protected authService: AuthService, protected authService: AuthService,
protected notifier: Notifier, protected notifier: Notifier,
protected screenService: ScreenService, protected screenService: ScreenService,
private i18n: I18n,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private videoService: VideoService private videoService: VideoService
) { ) {
this.titlePage = this.i18n('My videos') this.titlePage = $localize`My videos`
} }
ngOnInit () { ngOnInit () {
@ -97,8 +95,8 @@ export class MyAccountVideosComponent implements OnInit, DisableForReuseHook {
.map(k => parseInt(k, 10)) .map(k => parseInt(k, 10))
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to delete {{deleteLength}} videos?', { deleteLength: toDeleteVideosIds.length }), $localize`Do you really want to delete ${toDeleteVideosIds.length} videos?`,
this.i18n('Delete') $localize`Delete`
) )
if (res === false) return if (res === false) return
@ -114,8 +112,7 @@ export class MyAccountVideosComponent implements OnInit, DisableForReuseHook {
.pipe(toArray()) .pipe(toArray())
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('{{deleteLength}} videos deleted.', { deleteLength: toDeleteVideosIds.length })) this.notifier.success($localize`${toDeleteVideosIds.length} videos deleted.`)
this.selection = {} this.selection = {}
}, },
@ -125,15 +122,15 @@ export class MyAccountVideosComponent implements OnInit, DisableForReuseHook {
async deleteVideo (video: Video) { async deleteVideo (video: Video) {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to delete {{videoName}}?', { videoName: video.name }), $localize`Do you really want to delete ${video.name}?`,
this.i18n('Delete') $localize`Delete`
) )
if (res === false) return if (res === false) return
this.videoService.removeVideo(video.id) this.videoService.removeVideo(video.id)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Video {{videoName}} deleted.', { videoName: video.name })) this.notifier.success($localize`Video ${video.name} deleted.`)
this.removeVideoFromArray(video.id) this.removeVideoFromArray(video.id)
}, },

View File

@ -3,7 +3,6 @@ import { Notifier, UserService } from '@app/core'
import { FormReactive, FormValidatorService, VideoChangeOwnershipValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, VideoChangeOwnershipValidatorsService } from '@app/shared/shared-forms'
import { Video, VideoOwnershipService } from '@app/shared/shared-main' import { Video, VideoOwnershipService } from '@app/shared/shared-main'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-video-change-ownership', selector: 'my-video-change-ownership',
@ -25,9 +24,8 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni
private videoOwnershipService: VideoOwnershipService, private videoOwnershipService: VideoOwnershipService,
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService,
private modalService: NgbModal, private modalService: NgbModal
private i18n: I18n ) {
) {
super() super()
} }
@ -63,7 +61,7 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni
this.videoOwnershipService this.videoOwnershipService
.changeOwnership(this.video.id, username) .changeOwnership(this.video.id, username)
.subscribe( .subscribe(
() => this.notifier.success(this.i18n('Ownership change request sent.')), () => this.notifier.success($localize`Ownership change request sent.`),
err => this.notifier.error(err.message) err => this.notifier.error(err.message)
) )

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, ScreenService, ServerService, AuthUser } from '@app/core' import { AuthService, AuthUser, ScreenService, ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig } from '@shared/models' import { ServerConfig } from '@shared/models'
import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdown.component' import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdown.component'
@ -18,9 +17,8 @@ export class MyAccountComponent implements OnInit {
constructor ( constructor (
private serverService: ServerService, private serverService: ServerService,
private authService: AuthService, private authService: AuthService,
private screenService: ScreenService, private screenService: ScreenService
private i18n: I18n ) { }
) { }
get isBroadcastMessageDisplayed () { get isBroadcastMessageDisplayed () {
return this.screenService.isBroadcastMessageDisplayed return this.screenService.isBroadcastMessageDisplayed
@ -46,31 +44,31 @@ export class MyAccountComponent implements OnInit {
private buildMenu () { private buildMenu () {
const libraryEntries: TopMenuDropdownParam = { const libraryEntries: TopMenuDropdownParam = {
label: this.i18n('My library'), label: $localize`My library`,
children: [ children: [
{ {
label: this.i18n('My channels'), label: $localize`My channels`,
routerLink: '/my-account/video-channels', routerLink: '/my-account/video-channels',
iconName: 'channel' iconName: 'channel'
}, },
{ {
label: this.i18n('My videos'), label: $localize`My videos`,
routerLink: '/my-account/videos', routerLink: '/my-account/videos',
iconName: 'videos', iconName: 'videos',
isDisplayed: () => this.user.canSeeVideosLink isDisplayed: () => this.user.canSeeVideosLink
}, },
{ {
label: this.i18n('My playlists'), label: $localize`My playlists`,
routerLink: '/my-account/video-playlists', routerLink: '/my-account/video-playlists',
iconName: 'playlists' iconName: 'playlists'
}, },
{ {
label: this.i18n('My subscriptions'), label: $localize`My subscriptions`,
routerLink: '/my-account/subscriptions', routerLink: '/my-account/subscriptions',
iconName: 'subscriptions' iconName: 'subscriptions'
}, },
{ {
label: this.i18n('My history'), label: $localize`My history`,
routerLink: '/my-account/history/videos', routerLink: '/my-account/history/videos',
iconName: 'history' iconName: 'history'
} }
@ -87,25 +85,25 @@ export class MyAccountComponent implements OnInit {
} }
const miscEntries: TopMenuDropdownParam = { const miscEntries: TopMenuDropdownParam = {
label: this.i18n('Misc'), label: $localize`Misc`,
children: [ children: [
{ {
label: this.i18n('Muted accounts'), label: $localize`Muted accounts`,
routerLink: '/my-account/blocklist/accounts', routerLink: '/my-account/blocklist/accounts',
iconName: 'user-x' iconName: 'user-x'
}, },
{ {
label: this.i18n('Muted servers'), label: $localize`Muted servers`,
routerLink: '/my-account/blocklist/servers', routerLink: '/my-account/blocklist/servers',
iconName: 'peertube-x' iconName: 'peertube-x'
}, },
{ {
label: this.i18n('My abuse reports'), label: $localize`My abuse reports`,
routerLink: '/my-account/abuses', routerLink: '/my-account/abuses',
iconName: 'flag' iconName: 'flag'
}, },
{ {
label: this.i18n('Ownership changes'), label: $localize`Ownership changes`,
routerLink: '/my-account/ownership', routerLink: '/my-account/ownership',
iconName: 'download' iconName: 'download'
} }
@ -114,11 +112,11 @@ export class MyAccountComponent implements OnInit {
this.menuEntries = [ this.menuEntries = [
{ {
label: this.i18n('My settings'), label: $localize`My settings`,
routerLink: '/my-account/settings' routerLink: '/my-account/settings'
}, },
{ {
label: this.i18n('My notifications'), label: $localize`My notifications`,
routerLink: '/my-account/notifications' routerLink: '/my-account/notifications'
}, },
libraryEntries, libraryEntries,

View File

@ -2,7 +2,6 @@ import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { Notifier, UserService } from '@app/core' import { Notifier, UserService } from '@app/core'
import { FormReactive, FormValidatorService, ResetPasswordValidatorsService, UserValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, ResetPasswordValidatorsService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-login', selector: 'my-login',
@ -21,9 +20,8 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
private userService: UserService, private userService: UserService,
private notifier: Notifier, private notifier: Notifier,
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute
private i18n: I18n ) {
) {
super() super()
} }
@ -37,7 +35,7 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
this.verificationString = this.route.snapshot.queryParams['verificationString'] this.verificationString = this.route.snapshot.queryParams['verificationString']
if (!this.userId || !this.verificationString) { if (!this.userId || !this.verificationString) {
this.notifier.error(this.i18n('Unable to find user id or verification string.')) this.notifier.error($localize`Unable to find user id or verification string.`)
this.router.navigate([ '/' ]) this.router.navigate([ '/' ])
} }
} }
@ -46,7 +44,7 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
this.userService.resetPassword(this.userId, this.verificationString, this.form.value.password) this.userService.resetPassword(this.userId, this.verificationString, this.form.value.password)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Your password has been successfully reset!')) this.notifier.success($localize`Your password has been successfully reset!`)
this.router.navigate([ '/login' ]) this.router.navigate([ '/login' ])
}, },

View File

@ -1,8 +1,6 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { ServerService } from '@app/core' import { ServerService } from '@app/core'
import { VideoValidatorsService } from '@app/shared/shared-forms'
import { AdvancedSearch } from '@app/shared/shared-search' import { AdvancedSearch } from '@app/shared/shared-search'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig, VideoConstant } from '@shared/models' import { ServerConfig, VideoConstant } from '@shared/models'
@Component({ @Component({
@ -32,64 +30,62 @@ export class SearchFiltersComponent implements OnInit {
private serverConfig: ServerConfig private serverConfig: ServerConfig
constructor ( constructor (
private i18n: I18n,
private videoValidatorsService: VideoValidatorsService,
private serverService: ServerService private serverService: ServerService
) { ) {
this.publishedDateRanges = [ this.publishedDateRanges = [
{ {
id: 'any_published_date', id: 'any_published_date',
label: this.i18n('Any') label: $localize`Any`
}, },
{ {
id: 'today', id: 'today',
label: this.i18n('Today') label: $localize`Today`
}, },
{ {
id: 'last_7days', id: 'last_7days',
label: this.i18n('Last 7 days') label: $localize`Last 7 days`
}, },
{ {
id: 'last_30days', id: 'last_30days',
label: this.i18n('Last 30 days') label: $localize`Last 30 days`
}, },
{ {
id: 'last_365days', id: 'last_365days',
label: this.i18n('Last 365 days') label: $localize`Last 365 days`
} }
] ]
this.durationRanges = [ this.durationRanges = [
{ {
id: 'any_duration', id: 'any_duration',
label: this.i18n('Any') label: $localize`Any`
}, },
{ {
id: 'short', id: 'short',
label: this.i18n('Short (< 4 min)') label: $localize`Short (< 4 min)`
}, },
{ {
id: 'medium', id: 'medium',
label: this.i18n('Medium (4-10 min)') label: $localize`Medium (4-10 min)`
}, },
{ {
id: 'long', id: 'long',
label: this.i18n('Long (> 10 min)') label: $localize`Long (> 10 min)`
} }
] ]
this.sorts = [ this.sorts = [
{ {
id: '-match', id: '-match',
label: this.i18n('Relevance') label: $localize`Relevance`
}, },
{ {
id: '-publishedAt', id: '-publishedAt',
label: this.i18n('Publish date') label: $localize`Publish date`
}, },
{ {
id: '-views', id: '-views',
label: this.i18n('Views') label: $localize`Views`
} }
] ]
} }

View File

@ -7,7 +7,6 @@ import { Video, VideoChannel } from '@app/shared/shared-main'
import { AdvancedSearch, SearchService } from '@app/shared/shared-search' import { AdvancedSearch, SearchService } from '@app/shared/shared-search'
import { MiniatureDisplayOptions, VideoLinkType } from '@app/shared/shared-video-miniature' import { MiniatureDisplayOptions, VideoLinkType } from '@app/shared/shared-video-miniature'
import { MetaService } from '@ngx-meta/core' import { MetaService } from '@ngx-meta/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { SearchTargetType, ServerConfig } from '@shared/models' import { SearchTargetType, ServerConfig } from '@shared/models'
@Component({ @Component({
@ -52,7 +51,6 @@ export class SearchComponent implements OnInit, OnDestroy {
private lastSearchTarget: SearchTargetType private lastSearchTarget: SearchTargetType
constructor ( constructor (
private i18n: I18n,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private metaService: MetaService, private metaService: MetaService,
@ -170,8 +168,8 @@ export class SearchComponent implements OnInit, OnDestroy {
} }
this.notifier.error( this.notifier.error(
this.i18n('Search index is unavailable. Retrying with instance results instead.'), $localize`Search index is unavailable. Retrying with instance results instead.`,
this.i18n('Search error') $localize`Search error`
) )
this.advancedSearch.searchTarget = 'local' this.advancedSearch.searchTarget = 'local'
this.search() this.search()
@ -229,7 +227,7 @@ export class SearchComponent implements OnInit, OnDestroy {
private updateTitle () { private updateTitle () {
const suffix = this.currentSearch ? ' ' + this.currentSearch : '' const suffix = this.currentSearch ? ' ' + this.currentSearch : ''
this.metaService.setTitle(this.i18n('Search') + suffix) this.metaService.setTitle($localize`Search` + suffix)
} }
private updateUrlFromAdvancedSearch () { private updateUrlFromAdvancedSearch () {

View File

@ -5,7 +5,6 @@ import { AuthService, Notifier, UserService } from '@app/core'
import { HooksService } from '@app/core/plugins/hooks.service' import { HooksService } from '@app/core/plugins/hooks.service'
import { InstanceService } from '@app/shared/shared-instance' import { InstanceService } from '@app/shared/shared-instance'
import { NgbAccordion } from '@ng-bootstrap/ng-bootstrap' import { NgbAccordion } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserRegister } from '@shared/models' import { UserRegister } from '@shared/models'
import { About, ServerConfig } from '@shared/models/server' import { About, ServerConfig } from '@shared/models/server'
@ -42,9 +41,8 @@ export class RegisterComponent implements OnInit {
private notifier: Notifier, private notifier: Notifier,
private userService: UserService, private userService: UserService,
private instanceService: InstanceService, private instanceService: InstanceService,
private hooks: HooksService, private hooks: HooksService
private i18n: I18n ) {
) {
} }
get requiresEmailVerification () { get requiresEmailVerification () {
@ -114,7 +112,7 @@ export class RegisterComponent implements OnInit {
this.signupDone = true this.signupDone = true
if (this.requiresEmailVerification) { if (this.requiresEmailVerification) {
this.info = this.i18n('Now please check your emails to verify your account and complete signup.') this.info = $localize`Now please check your emails to verify your account and complete signup.`
return return
} }
@ -122,7 +120,7 @@ export class RegisterComponent implements OnInit {
this.authService.login(body.username, body.password) this.authService.login(body.username, body.password)
.subscribe( .subscribe(
() => { () => {
this.success = this.i18n('You are now logged in as {{username}}!', { username: body.username }) this.success = $localize`You are now logged in as ${body.username}!`
}, },
err => this.error = err.message err => this.error = err.message

View File

@ -1,7 +1,6 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { Notifier, RedirectService, ServerService, UserService } from '@app/core' import { Notifier, RedirectService, ServerService, UserService } from '@app/core'
import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig } from '@shared/models' import { ServerConfig } from '@shared/models'
@Component({ @Component({
@ -19,9 +18,8 @@ export class VerifyAccountAskSendEmailComponent extends FormReactive implements
private userService: UserService, private userService: UserService,
private serverService: ServerService, private serverService: ServerService,
private notifier: Notifier, private notifier: Notifier,
private redirectService: RedirectService, private redirectService: RedirectService
private i18n: I18n ) {
) {
super() super()
} }
@ -44,11 +42,7 @@ export class VerifyAccountAskSendEmailComponent extends FormReactive implements
this.userService.askSendVerifyEmail(email) this.userService.askSendVerifyEmail(email)
.subscribe( .subscribe(
() => { () => {
const message = this.i18n( this.notifier.success($localize`An email with verification link will be sent to ${email}.`)
'An email with verification link will be sent to {{email}}.',
{ email }
)
this.notifier.success(message)
this.redirectService.redirectToHomepage() this.redirectService.redirectToHomepage()
}, },

View File

@ -1,7 +1,6 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { AuthService, Notifier, UserService } from '@app/core' import { AuthService, Notifier, UserService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-verify-account-email', selector: 'my-verify-account-email',
@ -20,9 +19,8 @@ export class VerifyAccountEmailComponent implements OnInit {
private userService: UserService, private userService: UserService,
private authService: AuthService, private authService: AuthService,
private notifier: Notifier, private notifier: Notifier,
private route: ActivatedRoute, private route: ActivatedRoute
private i18n: I18n ) {
) {
} }
ngOnInit () { ngOnInit () {
@ -32,7 +30,7 @@ export class VerifyAccountEmailComponent implements OnInit {
this.isPendingEmail = queryParams['isPendingEmail'] === 'true' this.isPendingEmail = queryParams['isPendingEmail'] === 'true'
if (!this.userId || !this.verificationString) { if (!this.userId || !this.verificationString) {
this.notifier.error(this.i18n('Unable to find user id or verification string.')) this.notifier.error($localize`Unable to find user id or verification string.`)
} else { } else {
this.verifyEmail() this.verifyEmail()
} }

View File

@ -2,7 +2,6 @@ import { Subscription } from 'rxjs'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { MarkdownService } from '@app/core' import { MarkdownService } from '@app/core'
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-video-channel-about', selector: 'my-video-channel-about',
@ -17,7 +16,6 @@ export class VideoChannelAboutComponent implements OnInit, OnDestroy {
private videoChannelSub: Subscription private videoChannelSub: Subscription
constructor ( constructor (
private i18n: I18n,
private videoChannelService: VideoChannelService, private videoChannelService: VideoChannelService,
private markdownService: MarkdownService private markdownService: MarkdownService
) { } ) { }
@ -40,6 +38,6 @@ export class VideoChannelAboutComponent implements OnInit, OnDestroy {
getVideoChannelDescription () { getVideoChannelDescription () {
if (this.descriptionHTML) return this.descriptionHTML if (this.descriptionHTML) return this.descriptionHTML
return this.i18n('No description') return $localize`No description`
} }
} }

View File

@ -6,7 +6,6 @@ import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenServi
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main' import { VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-video-channel-videos', selector: 'my-video-channel-videos',
@ -23,7 +22,6 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
private videoChannelSub: Subscription private videoChannelSub: Subscription
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -38,7 +36,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
) { ) {
super() super()
this.titlePage = this.i18n('Published videos') this.titlePage = $localize`Published videos`
this.displayOptions = { this.displayOptions = {
...this.displayOptions, ...this.displayOptions,
avatar: false avatar: false
@ -72,7 +70,9 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
.getVideoChannelVideos(this.videoChannel, newPagination, this.sort, this.nsfwPolicy) .getVideoChannelVideos(this.videoChannel, newPagination, this.sort, this.nsfwPolicy)
.pipe( .pipe(
tap(({ total }) => { tap(({ total }) => {
this.titlePage = this.i18n(`{total, plural, =1 {Published 1 video} other {Published {{total}} videos}}`, { total }) this.titlePage = total === 1
? $localize`Published 1 video`
: $localize`Published ${total} videos`
}) })
) )
} }

View File

@ -6,7 +6,6 @@ import { ActivatedRoute } from '@angular/router'
import { AuthService, Notifier, RestExtractor, ScreenService } from '@app/core' import { AuthService, Notifier, RestExtractor, ScreenService } from '@app/core'
import { ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
templateUrl: './video-channels.component.html', templateUrl: './video-channels.component.html',
@ -23,7 +22,6 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
private routeSub: Subscription private routeSub: Subscription
constructor ( constructor (
private i18n: I18n,
private route: ActivatedRoute, private route: ActivatedRoute,
private notifier: Notifier, private notifier: Notifier,
private authService: AuthService, private authService: AuthService,
@ -59,14 +57,14 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
this.subscribeButton.unsubscribe() : this.subscribeButton.unsubscribe() :
this.subscribeButton.subscribe() this.subscribeButton.subscribe()
return false return false
}, undefined, this.i18n('Subscribe to the account')) }, undefined, $localize`Subscribe to the account`)
] ]
if (this.isUserLoggedIn()) this.hotkeysService.add(this.hotkeys) if (this.isUserLoggedIn()) this.hotkeysService.add(this.hotkeys)
this.links = [ this.links = [
{ label: this.i18n('VIDEOS'), routerLink: 'videos' }, { label: $localize`VIDEOS`, routerLink: 'videos' },
{ label: this.i18n('VIDEO PLAYLISTS'), routerLink: 'video-playlists' }, { label: $localize`VIDEO PLAYLISTS`, routerLink: 'video-playlists' },
{ label: this.i18n('ABOUT'), routerLink: 'about' } { label: $localize`ABOUT`, routerLink: 'about' }
] ]
} }
@ -91,6 +89,6 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
} }
activateCopiedMessage () { activateCopiedMessage () {
this.notifier.success(this.i18n('Username copied')) this.notifier.success($localize`Username copied`)
} }
} }

View File

@ -1,76 +1,75 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
@Injectable() @Injectable()
export class I18nPrimengCalendarService { export class I18nPrimengCalendarService {
private readonly calendarLocale: any = {} private readonly calendarLocale: any = {}
constructor (private i18n: I18n) { constructor () {
this.calendarLocale = { this.calendarLocale = {
firstDayOfWeek: 0, firstDayOfWeek: 0,
dayNames: [ dayNames: [
this.i18n('Sunday'), $localize`Sunday`,
this.i18n('Monday'), $localize`Monday`,
this.i18n('Tuesday'), $localize`Tuesday`,
this.i18n('Wednesday'), $localize`Wednesday`,
this.i18n('Thursday'), $localize`Thursday`,
this.i18n('Friday'), $localize`Friday`,
this.i18n('Saturday') $localize`Saturday`
], ],
dayNamesShort: [ dayNamesShort: [
this.i18n({ value: 'Sun', description: 'Day name short' }), $localize`:Day name short:Sun`,
this.i18n({ value: 'Mon', description: 'Day name short' }), $localize`:Day name short:Mon`,
this.i18n({ value: 'Tue', description: 'Day name short' }), $localize`:Day name short:Tue`,
this.i18n({ value: 'Wed', description: 'Day name short' }), $localize`:Day name short:Wed`,
this.i18n({ value: 'Thu', description: 'Day name short' }), $localize`:Day name short:Thu`,
this.i18n({ value: 'Fri', description: 'Day name short' }), $localize`:Day name short:Fri`,
this.i18n({ value: 'Sat', description: 'Day name short' }) $localize`:Day name short:Sat`
], ],
dayNamesMin: [ dayNamesMin: [
this.i18n({ value: 'Su', description: 'Day name min' }), $localize`:Day name min:Su`,
this.i18n({ value: 'Mo', description: 'Day name min' }), $localize`:Day name min:Mo`,
this.i18n({ value: 'Tu', description: 'Day name min' }), $localize`:Day name min:Tu`,
this.i18n({ value: 'We', description: 'Day name min' }), $localize`:Day name min:We`,
this.i18n({ value: 'Th', description: 'Day name min' }), $localize`:Day name min:Th`,
this.i18n({ value: 'Fr', description: 'Day name min' }), $localize`:Day name min:Fr`,
this.i18n({ value: 'Sa', description: 'Day name min' }) $localize`:Day name min:Sa`
], ],
monthNames: [ monthNames: [
this.i18n('January'), $localize`January`,
this.i18n('February'), $localize`February`,
this.i18n('March'), $localize`March`,
this.i18n('April'), $localize`April`,
this.i18n('May'), $localize`May`,
this.i18n('June'), $localize`June`,
this.i18n('July'), $localize`July`,
this.i18n('August'), $localize`August`,
this.i18n('September'), $localize`September`,
this.i18n('October'), $localize`October`,
this.i18n('November'), $localize`November`,
this.i18n('December') $localize`December`
], ],
monthNamesShort: [ monthNamesShort: [
this.i18n({ value: 'Jan', description: 'Month name short' }), $localize`:Month name short:Jan`,
this.i18n({ value: 'Feb', description: 'Month name short' }), $localize`:Month name short:Feb`,
this.i18n({ value: 'Mar', description: 'Month name short' }), $localize`:Month name short:Mar`,
this.i18n({ value: 'Apr', description: 'Month name short' }), $localize`:Month name short:Apr`,
this.i18n({ value: 'May', description: 'Month name short' }), $localize`:Month name short:May`,
this.i18n({ value: 'Jun', description: 'Month name short' }), $localize`:Month name short:Jun`,
this.i18n({ value: 'Jul', description: 'Month name short' }), $localize`:Month name short:Jul`,
this.i18n({ value: 'Aug', description: 'Month name short' }), $localize`:Month name short:Aug`,
this.i18n({ value: 'Sep', description: 'Month name short' }), $localize`:Month name short:Sep`,
this.i18n({ value: 'Oct', description: 'Month name short' }), $localize`:Month name short:Oct`,
this.i18n({ value: 'Nov', description: 'Month name short' }), $localize`:Month name short:Nov`,
this.i18n({ value: 'Dec', description: 'Month name short' }) $localize`:Month name short:Dec`
], ],
today: this.i18n('Today'), today: $localize`Today`,
clear: this.i18n('Clear') clear: $localize`Clear`
} }
} }
@ -86,9 +85,6 @@ export class I18nPrimengCalendarService {
} }
getDateFormat () { getDateFormat () {
return this.i18n({ return $localize`:Date format in this locale.:yy-mm-dd`
value: 'yy-mm-dd ',
description: 'Date format in this locale.'
})
} }
} }

View File

@ -7,7 +7,6 @@ import { removeElementFromArray } from '@app/helpers'
import { FormReactiveValidationMessages, FormValidatorService, SelectChannelItem, VideoValidatorsService } from '@app/shared/shared-forms' import { FormReactiveValidationMessages, FormValidatorService, SelectChannelItem, VideoValidatorsService } from '@app/shared/shared-forms'
import { InstanceService } from '@app/shared/shared-instance' import { InstanceService } from '@app/shared/shared-instance'
import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component'
@ -63,7 +62,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
private serverService: ServerService, private serverService: ServerService,
private instanceService: InstanceService, private instanceService: InstanceService,
private i18nPrimengCalendarService: I18nPrimengCalendarService, private i18nPrimengCalendarService: I18nPrimengCalendarService,
private i18n: I18n,
private ngZone: NgZone private ngZone: NgZone
) { ) {
this.calendarLocale = this.i18nPrimengCalendarService.getCalendarLocale() this.calendarLocale = this.i18nPrimengCalendarService.getCalendarLocale()
@ -137,8 +135,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
.subscribe(res => { .subscribe(res => {
this.videoLanguages = res.languages this.videoLanguages = res.languages
.map(l => res.about.instance.languages.includes(l.id) .map(l => res.about.instance.languages.includes(l.id)
? { ...l, group: this.i18n('Instance languages'), groupOrder: 0 } ? { ...l, group: $localize`Instance languages`, groupOrder: 0 }
: { ...l, group: this.i18n('All languages'), groupOrder: 1 }) : { ...l, group: $localize`All languages`, groupOrder: 1 })
.sort((a, b) => a.groupOrder - b.groupOrder) .sort((a, b) => a.groupOrder - b.groupOrder)
}) })
@ -148,8 +146,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
if (this.schedulePublicationPossible) { if (this.schedulePublicationPossible) {
this.videoPrivacies.push({ this.videoPrivacies.push({
id: this.SPECIAL_SCHEDULED_PRIVACY, id: this.SPECIAL_SCHEDULED_PRIVACY,
label: this.i18n('Scheduled'), label: $localize`Scheduled`,
description: this.i18n('Hide the video until a specific date') description: $localize`Hide the video until a specific date`
}) })
} }
}) })

View File

@ -4,10 +4,9 @@ import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@a
import { scrollToTop } from '@app/helpers' import { scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms' import { FormValidatorService } from '@app/shared/shared-forms'
import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
import { VideoSend } from './video-send'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPrivacy, VideoUpdate } from '@shared/models' import { VideoPrivacy, VideoUpdate } from '@shared/models'
import { VideoSend } from './video-send'
@Component({ @Component({
selector: 'my-video-import-torrent', selector: 'my-video-import-torrent',
@ -43,9 +42,8 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
protected videoService: VideoService, protected videoService: VideoService,
protected videoCaptionService: VideoCaptionService, protected videoCaptionService: VideoCaptionService,
private router: Router, private router: Router,
private videoImportService: VideoImportService, private videoImportService: VideoImportService
private i18n: I18n ) {
) {
super() super()
} }
@ -127,7 +125,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
.subscribe( .subscribe(
() => { () => {
this.isUpdatingVideo = false this.isUpdatingVideo = false
this.notifier.success(this.i18n('Video to import updated.')) this.notifier.success($localize`Video to import updated.`)
this.router.navigate([ '/my-account', 'video-imports' ]) this.router.navigate([ '/my-account', 'video-imports' ])
}, },

View File

@ -5,10 +5,9 @@ import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@a
import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers' import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms' import { FormValidatorService } from '@app/shared/shared-forms'
import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
import { VideoSend } from './video-send'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPrivacy, VideoUpdate } from '@shared/models' import { VideoPrivacy, VideoUpdate } from '@shared/models'
import { VideoSend } from './video-send'
@Component({ @Component({
selector: 'my-video-import-url', selector: 'my-video-import-url',
@ -42,9 +41,8 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
protected videoService: VideoService, protected videoService: VideoService,
protected videoCaptionService: VideoCaptionService, protected videoCaptionService: VideoCaptionService,
private router: Router, private router: Router,
private videoImportService: VideoImportService, private videoImportService: VideoImportService
private i18n: I18n ) {
) {
super() super()
} }
@ -137,7 +135,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
.subscribe( .subscribe(
() => { () => {
this.isUpdatingVideo = false this.isUpdatingVideo = false
this.notifier.success(this.i18n('Video to import updated.')) this.notifier.success($localize`Video to import updated.`)
this.router.navigate([ '/my-account', 'video-imports' ]) this.router.navigate([ '/my-account', 'video-imports' ])
}, },

View File

@ -7,7 +7,6 @@ import { scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms' import { FormValidatorService } from '@app/shared/shared-forms'
import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPrivacy } from '@shared/models' import { VideoPrivacy } from '@shared/models'
import { VideoSend } from './video-send' import { VideoSend } from './video-send'
@ -59,9 +58,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
protected videoService: VideoService, protected videoService: VideoService,
protected videoCaptionService: VideoCaptionService, protected videoCaptionService: VideoCaptionService,
private userService: UserService, private userService: UserService,
private router: Router, private router: Router
private i18n: I18n ) {
) {
super() super()
} }
@ -88,10 +86,10 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
if (this.videoUploaded === true) { if (this.videoUploaded === true) {
// FIXME: cannot concatenate strings inside i18n service :/ // FIXME: cannot concatenate strings inside i18n service :/
text = this.i18n('Your video was uploaded to your account and is private.') + ' ' + text = $localize`Your video was uploaded to your account and is private.` + ' ' +
this.i18n('But associated data (tags, description...) will be lost, are you sure you want to leave this page?') $localize`But associated data (tags, description...) will be lost, are you sure you want to leave this page?`
} else { } else {
text = this.i18n('Your video is not uploaded yet, are you sure you want to leave this page?') text = $localize`Your video is not uploaded yet, are you sure you want to leave this page?`
} }
return { return {
@ -111,9 +109,9 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
getAudioUploadLabel () { getAudioUploadLabel () {
const videofile = this.getVideoFile() const videofile = this.getVideoFile()
if (!videofile) return this.i18n('Upload') if (!videofile) return $localize`Upload`
return this.i18n('Upload {{videofileName}}', { videofileName: videofile.name }) return $localize`Upload ${videofile.name}`
} }
fileChange () { fileChange () {
@ -130,7 +128,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
this.firstStepError.emit() this.firstStepError.emit()
this.notifier.info(this.i18n('Upload cancelled')) this.notifier.info($localize`Upload cancelled`)
} }
} }
@ -242,7 +240,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
this.isUpdatingVideo = false this.isUpdatingVideo = false
this.isUploadingVideo = false this.isUploadingVideo = false
this.notifier.success(this.i18n('Video published.')) this.notifier.success($localize`Video published.`)
this.router.navigate([ '/videos/watch', video.uuid ]) this.router.navigate([ '/videos/watch', video.uuid ])
}, },
@ -260,14 +258,12 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
// Check global user quota // Check global user quota
const videoQuota = this.authService.getUser().videoQuota const videoQuota = this.authService.getUser().videoQuota
if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) { if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
const msg = this.i18n( const videoSizeBytes = bytePipes.transform(videofile.size, 0)
'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})', const videoQuotaUsedBytes = bytePipes.transform(this.userVideoQuotaUsed, 0)
{ const videoQuotaBytes = bytePipes.transform(videoQuota, 0)
videoSize: bytePipes.transform(videofile.size, 0),
videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0), const msg = $localize`Your video quota is exceeded with this video (
videoQuota: bytePipes.transform(videoQuota, 0) video size: ${videoSizeBytes}, used: ${videoQuotaUsedBytes}, quota: ${videoQuotaBytes})`
}
)
this.notifier.error(msg) this.notifier.error(msg)
return false return false
@ -282,14 +278,12 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
// Check daily user quota // Check daily user quota
const videoQuotaDaily = this.authService.getUser().videoQuotaDaily const videoQuotaDaily = this.authService.getUser().videoQuotaDaily
if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) { if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) {
const msg = this.i18n( const videoSizeBytes = bytePipes.transform(videofile.size, 0)
'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})', const quotaUsedDailyBytes = bytePipes.transform(this.userVideoQuotaUsedDaily, 0)
{ const quotaDailyBytes = bytePipes.transform(videoQuotaDaily, 0)
videoSize: bytePipes.transform(videofile.size, 0),
quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0), const msg = $localize`Your daily video quota is exceeded with this video (
quotaDaily: bytePipes.transform(videoQuotaDaily, 0) video size: ${videoSizeBytes}, used: ${quotaUsedDailyBytes}, quota: ${quotaDailyBytes})`
}
)
this.notifier.error(msg) this.notifier.error(msg)
return false return false

View File

@ -5,7 +5,6 @@ import { Notifier } from '@app/core'
import { FormReactive, FormValidatorService, SelectChannelItem } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService, SelectChannelItem } from '@app/shared/shared-forms'
import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoPrivacy } from '@shared/models' import { VideoPrivacy } from '@shared/models'
@Component({ @Component({
@ -31,9 +30,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
private notifier: Notifier, private notifier: Notifier,
private videoService: VideoService, private videoService: VideoService,
private loadingBar: LoadingBarService, private loadingBar: LoadingBarService,
private videoCaptionService: VideoCaptionService, private videoCaptionService: VideoCaptionService
private i18n: I18n ) {
) {
super() super()
} }
@ -78,7 +76,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
canDeactivate (): { canDeactivate: boolean, text?: string } { canDeactivate (): { canDeactivate: boolean, text?: string } {
if (this.updateDone === true) return { canDeactivate: true } if (this.updateDone === true) return { canDeactivate: true }
const text = this.i18n('You have unsaved changes! If you leave, your changes will be lost.') const text = $localize`You have unsaved changes! If you leave, your changes will be lost.`
for (const caption of this.videoCaptions) { for (const caption of this.videoCaptions) {
if (caption.action) return { canDeactivate: false, text } if (caption.action) return { canDeactivate: false, text }
@ -115,7 +113,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
this.updateDone = true this.updateDone = true
this.isUpdatingVideo = false this.isUpdatingVideo = false
this.loadingBar.useRef().complete() this.loadingBar.useRef().complete()
this.notifier.success(this.i18n('Video updated.')) this.notifier.success($localize`Video updated.`)
this.router.navigate([ '/videos/watch', this.video.uuid ]) this.router.navigate([ '/videos/watch', this.video.uuid ])
}, },

View File

@ -5,7 +5,6 @@ import { AuthService } from '@app/core/auth'
import { Account, Actor, DropdownAction, Video } from '@app/shared/shared-main' import { Account, Actor, DropdownAction, Video } from '@app/shared/shared-main'
import { CommentReportComponent } from '@app/shared/shared-moderation/report-modals/comment-report.component' import { CommentReportComponent } from '@app/shared/shared-moderation/report-modals/comment-report.component'
import { VideoComment, VideoCommentThreadTree } from '@app/shared/shared-video-comment' import { VideoComment, VideoCommentThreadTree } from '@app/shared/shared-video-comment'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { User, UserRight } from '@shared/models' import { User, UserRight } from '@shared/models'
@Component({ @Component({
@ -39,7 +38,6 @@ export class VideoCommentComponent implements OnInit, OnChanges {
commentUser: User commentUser: User
constructor ( constructor (
private i18n: I18n,
private markdownService: MarkdownService, private markdownService: MarkdownService,
private authService: AuthService, private authService: AuthService,
private userService: UserService, private userService: UserService,
@ -138,7 +136,7 @@ export class VideoCommentComponent implements OnInit, OnChanges {
if (this.isUserLoggedIn() && this.comment.isDeleted === false && this.authService.getUser().account.id !== this.comment.account.id) { if (this.isUserLoggedIn() && this.comment.isDeleted === false && this.authService.getUser().account.id !== this.comment.account.id) {
this.prependModerationActions = [ this.prependModerationActions = [
{ {
label: this.i18n('Report comment'), label: $localize`Report comment`,
handler: () => this.showReportModal() handler: () => this.showReportModal()
} }
] ]

View File

@ -5,7 +5,6 @@ import { AuthService, ComponentPagination, ConfirmService, hasMoreItems, Notifie
import { HooksService } from '@app/core/plugins/hooks.service' import { HooksService } from '@app/core/plugins/hooks.service'
import { Syndication, VideoDetails } from '@app/shared/shared-main' import { Syndication, VideoDetails } from '@app/shared/shared-main'
import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment' import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-video-comments', selector: 'my-video-comments',
@ -43,7 +42,6 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
private confirmService: ConfirmService, private confirmService: ConfirmService,
private videoCommentService: VideoCommentService, private videoCommentService: VideoCommentService,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private i18n: I18n,
private hooks: HooksService private hooks: HooksService
) {} ) {}
@ -162,12 +160,12 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
let message = 'Do you really want to delete this comment?' let message = 'Do you really want to delete this comment?'
if (commentToDelete.isLocal || this.video.isLocal) { if (commentToDelete.isLocal || this.video.isLocal) {
message += this.i18n(' The deletion will be sent to remote instances so they can reflect the change.') message += $localize` The deletion will be sent to remote instances so they can reflect the change.`
} else { } else {
message += this.i18n(' It is a remote comment, so the deletion will only be effective on your instance.') message += $localize` It is a remote comment, so the deletion will only be effective on your instance.`
} }
const res = await this.confirmService.confirm(message, this.i18n('Delete')) const res = await this.confirmService.confirm(message, $localize`Delete`)
if (res === false) return if (res === false) return
this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id) this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)

View File

@ -4,10 +4,9 @@ import { AuthService, Notifier, SessionStorageService, User, UserService } from
import { Video } from '@app/shared/shared-main' import { Video } from '@app/shared/shared-main'
import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature' import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature'
import { VideoPlaylist } from '@app/shared/shared-video-playlist' import { VideoPlaylist } from '@app/shared/shared-video-playlist'
import { I18n } from '@ngx-translate/i18n-polyfill' import { UserLocalStorageKeys } from '@root-helpers/users'
import { RecommendationInfo } from './recommendation-info.model' import { RecommendationInfo } from './recommendation-info.model'
import { RecommendedVideosStore } from './recommended-videos.store' import { RecommendedVideosStore } from './recommended-videos.store'
import { UserLocalStorageKeys } from '@root-helpers/users'
@Component({ @Component({
selector: 'my-recommended-videos', selector: 'my-recommended-videos',
@ -38,7 +37,6 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
private userService: UserService, private userService: UserService,
private authService: AuthService, private authService: AuthService,
private notifier: Notifier, private notifier: Notifier,
private i18n: I18n,
private store: RecommendedVideosStore, private store: RecommendedVideosStore,
private sessionStorageService: SessionStorageService private sessionStorageService: SessionStorageService
) { ) {
@ -58,7 +56,7 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
) )
} }
this.autoPlayNextVideoTooltip = this.i18n('When active, the next video is automatically played after the current one.') this.autoPlayNextVideoTooltip = $localize`When active, the next video is automatically played after the current one.`
} }
ngOnInit () { ngOnInit () {

View File

@ -1,28 +1,23 @@
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Pipe({ @Pipe({
name: 'myVideoDurationFormatter' name: 'myVideoDurationFormatter'
}) })
export class VideoDurationPipe implements PipeTransform { export class VideoDurationPipe implements PipeTransform {
constructor (private i18n: I18n) {
}
transform (value: number): string { transform (value: number): string {
const hours = Math.floor(value / 3600) const hours = Math.floor(value / 3600)
const minutes = Math.floor((value % 3600) / 60) const minutes = Math.floor((value % 3600) / 60)
const seconds = value % 60 const seconds = value % 60
if (hours > 0) { if (hours > 0) {
return this.i18n('{{hours}} h {{minutes}} min {{seconds}} sec', { hours, minutes, seconds }) return $localize`${hours} h ${minutes} min ${seconds} sec`
} }
if (minutes > 0) { if (minutes > 0) {
return this.i18n('{{minutes}} min {{seconds}} sec', { minutes, seconds }) return $localize`${minutes} min ${seconds} sec`
} }
return this.i18n('{{seconds}} sec', { seconds }) return $localize`${seconds} sec`
} }
} }

View File

@ -1,9 +1,8 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core' import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core'
import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { I18n } from '@ngx-translate/i18n-polyfill' import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models' import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models'
@Component({ @Component({
@ -36,7 +35,6 @@ export class VideoWatchPlaylistComponent {
private userService: UserService, private userService: UserService,
private auth: AuthService, private auth: AuthService,
private notifier: Notifier, private notifier: Notifier,
private i18n: I18n,
private videoPlaylist: VideoPlaylistService, private videoPlaylist: VideoPlaylistService,
private localStorageService: LocalStorageService, private localStorageService: LocalStorageService,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
@ -189,13 +187,13 @@ export class VideoWatchPlaylistComponent {
private setAutoPlayNextVideoPlaylistSwitchText () { private setAutoPlayNextVideoPlaylistSwitchText () {
this.autoPlayNextVideoPlaylistSwitchText = this.autoPlayNextVideoPlaylist this.autoPlayNextVideoPlaylistSwitchText = this.autoPlayNextVideoPlaylist
? this.i18n('Stop autoplaying next video') ? $localize`Stop autoplaying next video`
: this.i18n('Autoplay next video') : $localize`Autoplay next video`
} }
private setLoopPlaylistSwitchText () { private setLoopPlaylistSwitchText () {
this.loopPlaylistSwitchText = this.loopPlaylist this.loopPlaylistSwitchText = this.loopPlaylist
? this.i18n('Stop looping playlist videos') ? $localize`Stop looping playlist videos`
: this.i18n('Loop playlist videos') : $localize`Loop playlist videos`
} }
} }

View File

@ -14,7 +14,6 @@ import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
import { VideoDownloadComponent } from '@app/shared/shared-video-miniature' import { VideoDownloadComponent } from '@app/shared/shared-video-miniature'
import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { MetaService } from '@ngx-meta/core' import { MetaService } from '@ngx-meta/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { ServerConfig, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' import { ServerConfig, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models'
import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage' import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage'
@ -97,16 +96,15 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private zone: NgZone, private zone: NgZone,
private redirectService: RedirectService, private redirectService: RedirectService,
private videoCaptionService: VideoCaptionService, private videoCaptionService: VideoCaptionService,
private i18n: I18n,
private hotkeysService: HotkeysService, private hotkeysService: HotkeysService,
private hooks: HooksService, private hooks: HooksService,
private location: PlatformLocation, private location: PlatformLocation,
@Inject(LOCALE_ID) private localeId: string @Inject(LOCALE_ID) private localeId: string
) { ) {
this.tooltipLike = this.i18n('Like this video') this.tooltipLike = $localize`Like this video`
this.tooltipDislike = this.i18n('Dislike this video') this.tooltipDislike = $localize`Dislike this video`
this.tooltipSupport = this.i18n('Support options for this video') this.tooltipSupport = $localize`Support options for this video`
this.tooltipSaveToPlaylist = this.i18n('Save to playlist') this.tooltipSaveToPlaylist = $localize`Save to playlist`
} }
get user () { get user () {
@ -188,7 +186,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
getRatePopoverText () { getRatePopoverText () {
if (this.isUserLoggedIn()) return undefined if (this.isUserLoggedIn()) return undefined
return this.i18n('You need to be connected to rate this content.') return $localize`You need to be connected to rate this content.`
} }
showMoreDescription () { showMoreDescription () {
@ -409,10 +407,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
} }
private setVideoLikesBarTooltipText () { private setVideoLikesBarTooltipText () {
this.likesBarTooltipText = this.i18n('{{likesNumber}} likes / {{dislikesNumber}} dislikes', { this.likesBarTooltipText = `${this.video.likes} likes / ${this.video.dislikes} dislikes`
likesNumber: this.video.likes,
dislikesNumber: this.video.dislikes
})
} }
private handleError (err: any) { private handleError (err: any) {
@ -465,8 +460,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
if (this.isVideoBlur(this.video)) { if (this.isVideoBlur(this.video)) {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('This video contains mature or explicit content. Are you sure you want to watch it?'), $localize`This video contains mature or explicit content. Are you sure you want to watch it?`,
this.i18n('Mature or explicit content') $localize`Mature or explicit content`
) )
if (res === false) return this.location.back() if (res === false) return this.location.back()
} }
@ -515,9 +510,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
*/ */
this.player.upnext({ this.player.upnext({
timeout: 10000, // 10s timeout: 10000, // 10s
headText: this.i18n('Up Next'), headText: $localize`Up Next`,
cancelText: this.i18n('Cancel'), cancelText: $localize`Cancel`,
suspendedText: this.i18n('Autoplay is suspended'), suspendedText: $localize`Autoplay is suspended`,
getTitle: () => this.nextVideoTitle, getTitle: () => this.nextVideoTitle,
next: () => this.zone.run(() => this.autoplayNext()), next: () => this.zone.run(() => this.autoplayNext()),
condition: () => { condition: () => {
@ -781,22 +776,22 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private initHotkeys () { private initHotkeys () {
this.hotkeys = [ this.hotkeys = [
// These hotkeys are managed by the player // These hotkeys are managed by the player
new Hotkey('f', e => e, undefined, this.i18n('Enter/exit fullscreen (requires player focus)')), new Hotkey('f', e => e, undefined, $localize`Enter/exit fullscreen (requires player focus)`),
new Hotkey('space', e => e, undefined, this.i18n('Play/Pause the video (requires player focus)')), new Hotkey('space', e => e, undefined, $localize`Play/Pause the video (requires player focus)`),
new Hotkey('m', e => e, undefined, this.i18n('Mute/unmute the video (requires player focus)')), new Hotkey('m', e => e, undefined, $localize`Mute/unmute the video (requires player focus)`),
new Hotkey('0-9', e => e, undefined, this.i18n('Skip to a percentage of the video: 0 is 0% and 9 is 90% (requires player focus)')), new Hotkey('0-9', e => e, undefined, $localize`Skip to a percentage of the video: 0 is 0% and 9 is 90% (requires player focus)`),
new Hotkey('up', e => e, undefined, this.i18n('Increase the volume (requires player focus)')), new Hotkey('up', e => e, undefined, $localize`Increase the volume (requires player focus)`),
new Hotkey('down', e => e, undefined, this.i18n('Decrease the volume (requires player focus)')), new Hotkey('down', e => e, undefined, $localize`Decrease the volume (requires player focus)`),
new Hotkey('right', e => e, undefined, this.i18n('Seek the video forward (requires player focus)')), new Hotkey('right', e => e, undefined, $localize`Seek the video forward (requires player focus)`),
new Hotkey('left', e => e, undefined, this.i18n('Seek the video backward (requires player focus)')), new Hotkey('left', e => e, undefined, $localize`Seek the video backward (requires player focus)`),
new Hotkey('>', e => e, undefined, this.i18n('Increase playback rate (requires player focus)')), new Hotkey('>', e => e, undefined, $localize`Increase playback rate (requires player focus)`),
new Hotkey('<', e => e, undefined, this.i18n('Decrease playback rate (requires player focus)')), new Hotkey('<', e => e, undefined, $localize`Decrease playback rate (requires player focus)`),
new Hotkey('.', e => e, undefined, this.i18n('Navigate in the video frame by frame (requires player focus)')) new Hotkey('.', e => e, undefined, $localize`Navigate in the video frame by frame (requires player focus)`)
] ]
if (this.isUserLoggedIn()) { if (this.isUserLoggedIn()) {
@ -804,17 +799,17 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
new Hotkey('shift+l', () => { new Hotkey('shift+l', () => {
this.setLike() this.setLike()
return false return false
}, undefined, this.i18n('Like the video')), }, undefined, $localize`Like the video`),
new Hotkey('shift+d', () => { new Hotkey('shift+d', () => {
this.setDislike() this.setDislike()
return false return false
}, undefined, this.i18n('Dislike the video')), }, undefined, $localize`Dislike the video`),
new Hotkey('shift+s', () => { new Hotkey('shift+s', () => {
this.subscribeButton.subscribed ? this.subscribeButton.unsubscribe() : this.subscribeButton.subscribe() this.subscribeButton.subscribed ? this.subscribeButton.unsubscribe() : this.subscribeButton.subscribe()
return false return false
}, undefined, this.i18n('Subscribe to the account')) }, undefined, $localize`Subscribe to the account`)
]) ])
} }

View File

@ -5,7 +5,6 @@ import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserRight, VideoFilter, VideoSortField } from '@shared/models' import { UserRight, VideoFilter, VideoSortField } from '@shared/models'
@Component({ @Component({
@ -21,7 +20,6 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
useUserVideoPreferences = true useUserVideoPreferences = true
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -35,7 +33,7 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
) { ) {
super() super()
this.titlePage = i18n('Local videos') this.titlePage = $localize`Local videos`
} }
ngOnInit () { ngOnInit () {

View File

@ -5,7 +5,6 @@ import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@shared/models'
@Component({ @Component({
@ -20,7 +19,6 @@ export class VideoMostLikedComponent extends AbstractVideoList implements OnInit
useUserVideoPreferences = true useUserVideoPreferences = true
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -40,8 +38,8 @@ export class VideoMostLikedComponent extends AbstractVideoList implements OnInit
this.generateSyndicationList() this.generateSyndicationList()
this.titlePage = this.i18n('Most liked videos') this.titlePage = $localize`Most liked videos`
this.titleTooltip = this.i18n('Videos that have the higher number of likes.') this.titleTooltip = $localize`Videos that have the higher number of likes.`
} }
getVideosObservable (page: number) { getVideosObservable (page: number) {

View File

@ -5,7 +5,6 @@ import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@shared/models'
@Component({ @Component({
@ -21,7 +20,6 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
useUserVideoPreferences = true useUserVideoPreferences = true
constructor ( constructor (
protected i18n: I18n,
protected route: ActivatedRoute, protected route: ActivatedRoute,
protected serverService: ServerService, protected serverService: ServerService,
protected router: Router, protected router: Router,
@ -35,7 +33,7 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
) { ) {
super() super()
this.titlePage = i18n('Recently added') this.titlePage = $localize`Recently added`
} }
ngOnInit () { ngOnInit () {

View File

@ -5,7 +5,6 @@ import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@shared/models'
@Component({ @Component({
@ -20,7 +19,6 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
useUserVideoPreferences = true useUserVideoPreferences = true
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -45,14 +43,11 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
const trendingDays = config.trending.videos.intervalDays const trendingDays = config.trending.videos.intervalDays
if (trendingDays === 1) { if (trendingDays === 1) {
this.titlePage = this.i18n('Trending for the last 24 hours') this.titlePage = $localize`Trending for the last 24 hours`
this.titleTooltip = this.i18n('Trending videos are those totalizing the greatest number of views during the last 24 hours') this.titleTooltip = $localize`Trending videos are those totalizing the greatest number of views during the last 24 hours`
} else { } else {
this.titlePage = this.i18n('Trending for the last {{days}} days', { days: trendingDays }) this.titlePage = `Trending for the last ${trendingDays} days`
this.titleTooltip = this.i18n( this.titleTooltip = `Trending videos are those totalizing the greatest number of views during the last ${trendingDays} days`
'Trending videos are those totalizing the greatest number of views during the last {{days}} days',
{ days: trendingDays }
)
} }
}) })
} }

View File

@ -3,10 +3,8 @@ import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' import { AuthService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'
import { HooksService } from '@app/core/plugins/hooks.service' import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main'
import { UserSubscriptionService } from '@app/shared/shared-user-subscription' import { UserSubscriptionService } from '@app/shared/shared-user-subscription'
import { AbstractVideoList, OwnerDisplayType } from '@app/shared/shared-video-miniature' import { AbstractVideoList, OwnerDisplayType } from '@app/shared/shared-video-miniature'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@shared/models'
@Component({ @Component({
@ -21,7 +19,6 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement
groupByDate = true groupByDate = true
constructor ( constructor (
protected i18n: I18n,
protected router: Router, protected router: Router,
protected serverService: ServerService, protected serverService: ServerService,
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -31,15 +28,14 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement
protected screenService: ScreenService, protected screenService: ScreenService,
protected storageService: LocalStorageService, protected storageService: LocalStorageService,
private userSubscription: UserSubscriptionService, private userSubscription: UserSubscriptionService,
private videoService: VideoService,
private hooks: HooksService private hooks: HooksService
) { ) {
super() super()
this.titlePage = i18n('Videos from your subscriptions') this.titlePage = $localize`Videos from your subscriptions`
this.actions.push({ this.actions.push({
routerLink: '/my-account/subscriptions', routerLink: '/my-account/subscriptions',
label: i18n('Subscriptions'), label: $localize`Subscriptions`,
iconName: 'cog' iconName: 'cog'
}) })
} }

View File

@ -12,12 +12,11 @@ import { CustomModalComponent } from '@app/modal/custom-modal.component'
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component' import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
import { WelcomeModalComponent } from '@app/modal/welcome-modal.component' import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { I18n } from '@ngx-translate/i18n-polyfill' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { getShortLocale, is18nPath } from '@shared/core-utils/i18n' import { getShortLocale, is18nPath } from '@shared/core-utils/i18n'
import { BroadcastMessageLevel, ServerConfig, UserRole } from '@shared/models' import { BroadcastMessageLevel, ServerConfig, UserRole } from '@shared/models'
import { MenuService } from './core/menu/menu.service' import { MenuService } from './core/menu/menu.service'
import { POP_STATE_MODAL_DISMISS } from './helpers' import { POP_STATE_MODAL_DISMISS } from './helpers'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { InstanceService } from './shared/shared-instance' import { InstanceService } from './shared/shared-instance'
@Component({ @Component({
@ -40,7 +39,6 @@ export class AppComponent implements OnInit, AfterViewInit {
constructor ( constructor (
@Inject(DOCUMENT) private document: Document, @Inject(DOCUMENT) private document: Document,
@Inject(LOCALE_ID) private localeId: string, @Inject(LOCALE_ID) private localeId: string,
private i18n: I18n,
private viewportScroller: ViewportScroller, private viewportScroller: ViewportScroller,
private router: Router, private router: Router,
private authService: AuthService, private authService: AuthService,
@ -288,37 +286,37 @@ export class AppComponent implements OnInit, AfterViewInit {
new Hotkey(['/', 's'], (event: KeyboardEvent): boolean => { new Hotkey(['/', 's'], (event: KeyboardEvent): boolean => {
document.getElementById('search-video').focus() document.getElementById('search-video').focus()
return false return false
}, undefined, this.i18n('Focus the search bar')), }, undefined, $localize`Focus the search bar`),
new Hotkey('b', (event: KeyboardEvent): boolean => { new Hotkey('b', (event: KeyboardEvent): boolean => {
this.menu.toggleMenu() this.menu.toggleMenu()
return false return false
}, undefined, this.i18n('Toggle the left menu')), }, undefined, $localize`Toggle the left menu`),
new Hotkey('g o', (event: KeyboardEvent): boolean => { new Hotkey('g o', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/overview' ]) this.router.navigate([ '/videos/overview' ])
return false return false
}, undefined, this.i18n('Go to the discover videos page')), }, undefined, $localize`Go to the discover videos page`),
new Hotkey('g t', (event: KeyboardEvent): boolean => { new Hotkey('g t', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/trending' ]) this.router.navigate([ '/videos/trending' ])
return false return false
}, undefined, this.i18n('Go to the trending videos page')), }, undefined, $localize`Go to the trending videos page`),
new Hotkey('g r', (event: KeyboardEvent): boolean => { new Hotkey('g r', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/recently-added' ]) this.router.navigate([ '/videos/recently-added' ])
return false return false
}, undefined, this.i18n('Go to the recently added videos page')), }, undefined, $localize`Go to the recently added videos page`),
new Hotkey('g l', (event: KeyboardEvent): boolean => { new Hotkey('g l', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/local' ]) this.router.navigate([ '/videos/local' ])
return false return false
}, undefined, this.i18n('Go to the local videos page')), }, undefined, $localize`Go to the local videos page`),
new Hotkey('g u', (event: KeyboardEvent): boolean => { new Hotkey('g u', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/upload' ]) this.router.navigate([ '/videos/upload' ])
return false return false
}, undefined, this.i18n('Go to the videos upload page')) }, undefined, $localize`Go to the videos upload page`)
]) ])
} }
} }

View File

@ -81,21 +81,7 @@ registerLocaleData(localeOc, 'oc')
{ {
provide: APP_BASE_HREF, provide: APP_BASE_HREF,
useValue: '/' useValue: '/'
}, }
{
provide: TRANSLATIONS,
useFactory: (locale: string) => {
// Default locale, nothing to translate
const completeLocale = getCompleteLocale(locale)
if (isDefaultLocale(completeLocale)) return ''
const fileLocale = buildFileLocale(locale)
return require(`raw-loader!../locale/angular.${fileLocale}.xlf`).default
},
deps: [ LOCALE_ID ]
},
{ provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }
] ]
}) })
export class AppModule {} export class AppModule {}

View File

@ -6,7 +6,6 @@ import { Injectable } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { Notifier } from '@app/core/notification/notifier.service' import { Notifier } from '@app/core/notification/notifier.service'
import { objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index' import { objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models' import { MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models'
import { environment } from '../../../environments/environment' import { environment } from '../../../environments/environment'
import { RestExtractor } from '../rest/rest-extractor.service' import { RestExtractor } from '../rest/rest-extractor.service'
@ -48,9 +47,8 @@ export class AuthService {
private notifier: Notifier, private notifier: Notifier,
private hotkeysService: HotkeysService, private hotkeysService: HotkeysService,
private restExtractor: RestExtractor, private restExtractor: RestExtractor,
private router: Router, private router: Router
private i18n: I18n ) {
) {
this.loginChanged = new Subject<AuthStatus>() this.loginChanged = new Subject<AuthStatus>()
this.loginChangedSource = this.loginChanged.asObservable() this.loginChangedSource = this.loginChanged.asObservable()
@ -62,19 +60,19 @@ export class AuthService {
new Hotkey('m s', (event: KeyboardEvent): boolean => { new Hotkey('m s', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/subscriptions' ]) this.router.navigate([ '/videos/subscriptions' ])
return false return false
}, undefined, this.i18n('Go to my subscriptions')), }, undefined, $localize`Go to my subscriptions`),
new Hotkey('m v', (event: KeyboardEvent): boolean => { new Hotkey('m v', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/my-account/videos' ]) this.router.navigate([ '/my-account/videos' ])
return false return false
}, undefined, this.i18n('Go to my videos')), }, undefined, $localize`Go to my videos`),
new Hotkey('m i', (event: KeyboardEvent): boolean => { new Hotkey('m i', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/my-account/video-imports' ]) this.router.navigate([ '/my-account/video-imports' ])
return false return false
}, undefined, this.i18n('Go to my imports')), }, undefined, $localize`Go to my imports`),
new Hotkey('m c', (event: KeyboardEvent): boolean => { new Hotkey('m c', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/my-account/video-channels' ]) this.router.navigate([ '/my-account/video-channels' ])
return false return false
}, undefined, this.i18n('Go to my channels')) }, undefined, $localize`Go to my channels`)
] ]
} }
@ -97,14 +95,12 @@ export class AuthService {
let errorMessage = error.message let errorMessage = error.message
if (error.status === 403) { if (error.status === 403) {
errorMessage = this.i18n('Cannot retrieve OAuth Client credentials: {{errorText}}.\n', { errorText: error.text }) errorMessage = $localize`Cannot retrieve OAuth Client credentials: ${error.text}.
errorMessage += this.i18n( Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.`
'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'
)
} }
// We put a bigger timeout: this is an important message // We put a bigger timeout: this is an important message
this.notifier.error(errorMessage, this.i18n('Error'), 7000) this.notifier.error(errorMessage, $localize`Error`, 7000)
} }
) )
} }
@ -216,7 +212,7 @@ export class AuthService {
this.router.navigate([ '/login' ]) this.router.navigate([ '/login' ])
return observableThrowError({ return observableThrowError({
error: this.i18n('You need to reconnect.') error: $localize`You need to reconnect.`
}) })
}), }),
share() share()

View File

@ -1,7 +1,6 @@
import { Component, OnInit, OnDestroy, Input } from '@angular/core' import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
import { I18n } from '@ngx-translate/i18n-polyfill' import { Component, Input, OnDestroy, OnInit } from '@angular/core'
import { HotkeysService, Hotkey } from 'angular2-hotkeys'
@Component({ @Component({
selector : 'my-hotkeys-cheatsheet', selector : 'my-hotkeys-cheatsheet',
@ -9,16 +8,15 @@ import { HotkeysService, Hotkey } from 'angular2-hotkeys'
styleUrls: [ './hotkeys.component.scss' ] styleUrls: [ './hotkeys.component.scss' ]
}) })
export class CheatSheetComponent implements OnInit, OnDestroy { export class CheatSheetComponent implements OnInit, OnDestroy {
@Input() title = this.i18n('Keyboard Shortcuts:') @Input() title = $localize`Keyboard Shortcuts:`
helpVisible = false helpVisible = false
subscription: Subscription subscription: Subscription
hotkeys: Hotkey[] hotkeys: Hotkey[]
constructor ( constructor (
private hotkeysService: HotkeysService, private hotkeysService: HotkeysService
private i18n: I18n ) {}
) {}
public ngOnInit (): void { public ngOnInit (): void {
this.subscription = this.hotkeysService.cheatSheetToggle.subscribe((isOpen) => { this.subscription = this.hotkeysService.cheatSheetToggle.subscribe((isOpen) => {

View File

@ -1,30 +1,26 @@
import { Injectable } from '@angular/core'
import { MessageService } from 'primeng/api' import { MessageService } from 'primeng/api'
import { I18n } from '@ngx-translate/i18n-polyfill' import { Injectable } from '@angular/core'
@Injectable() @Injectable()
export class Notifier { export class Notifier {
readonly TIMEOUT = 5000 readonly TIMEOUT = 5000
constructor ( constructor (private messageService: MessageService) { }
private i18n: I18n,
private messageService: MessageService) {
}
info (text: string, title?: string, timeout?: number) { info (text: string, title?: string, timeout?: number) {
if (!title) title = this.i18n('Info') if (!title) title = $localize`Info`
return this.notify('info', text, title, timeout) return this.notify('info', text, title, timeout)
} }
error (text: string, title?: string, timeout?: number) { error (text: string, title?: string, timeout?: number) {
if (!title) title = this.i18n('Error') if (!title) title = $localize`Error`
return this.notify('error', text, title, timeout) return this.notify('error', text, title, timeout)
} }
success (text: string, title?: string, timeout?: number) { success (text: string, title?: string, timeout?: number) {
if (!title) title = this.i18n('Success') if (!title) title = $localize`Success`
return this.notify('success', text, title, timeout) return this.notify('success', text, title, timeout)
} }

View File

@ -2,16 +2,12 @@ import { throwError as observableThrowError } from 'rxjs'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { dateToHuman } from '@app/helpers' import { dateToHuman } from '@app/helpers'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ResultList } from '@shared/models' import { ResultList } from '@shared/models'
@Injectable() @Injectable()
export class RestExtractor { export class RestExtractor {
constructor ( constructor (private router: Router) { }
private router: Router,
private i18n: I18n
) { }
extractDataBool () { extractDataBool () {
return true return true
@ -62,19 +58,18 @@ export class RestExtractor {
} else if (err.error && err.error.error) { } else if (err.error && err.error.error) {
errorMessage = err.error.error errorMessage = err.error.error
} else if (err.status === 413) { } else if (err.status === 413) {
errorMessage = this.i18n( errorMessage = $localize`Request is too large for the server.
'Request is too large for the server. Please contact you administrator if you want to increase the limit size.' Please contact you administrator if you want to increase the limit size.`
)
} else if (err.status === 429) { } else if (err.status === 429) {
const secondsLeft = err.headers.get('retry-after') const secondsLeft = err.headers.get('retry-after')
if (secondsLeft) { if (secondsLeft) {
const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60) const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60)
errorMessage = this.i18n('Too many attempts, please try again after {{minutesLeft}} minutes.', { minutesLeft }) errorMessage = $localize`Too many attempts, please try again after ${minutesLeft} minutes.`
} else { } else {
errorMessage = this.i18n('Too many attempts, please try again later.') errorMessage = $localize`Too many attempts, please try again later.`
} }
} else if (err.status === 500) { } else if (err.status === 500) {
errorMessage = this.i18n('Server error. Please retry later.') errorMessage = $localize`Server error. Please retry later.`
} }
errorMessage = errorMessage ? errorMessage : 'Unknown error.' errorMessage = errorMessage ? errorMessage : 'Unknown error.'

View File

@ -2,7 +2,6 @@ import { Observable } from 'rxjs'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { CanDeactivate } from '@angular/router' import { CanDeactivate } from '@angular/router'
import { ConfirmService } from '@app/core/confirm' import { ConfirmService } from '@app/core/confirm'
import { I18n } from '@ngx-translate/i18n-polyfill'
export type CanComponentDeactivateResult = { text?: string, canDeactivate: Observable<boolean> | boolean } export type CanComponentDeactivateResult = { text?: string, canDeactivate: Observable<boolean> | boolean }
@ -12,18 +11,16 @@ export interface CanComponentDeactivate {
@Injectable() @Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> { export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
constructor (
private confirmService: ConfirmService, constructor (private confirmService: ConfirmService) { }
private i18n: I18n
) { }
canDeactivate (component: CanComponentDeactivate) { canDeactivate (component: CanComponentDeactivate) {
const result = component.canDeactivate() const result = component.canDeactivate()
const text = result.text || this.i18n('All unsaved data will be lost, are you sure you want to leave this page?') const text = result.text || $localize`All unsaved data will be lost, are you sure you want to leave this page?`
return result.canDeactivate || this.confirmService.confirm( return result.canDeactivate || this.confirmService.confirm(
text, text,
this.i18n('Warning') $localize`Warning`
) )
} }

View File

@ -5,7 +5,6 @@ import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { AuthService } from '@app/core/auth' import { AuthService } from '@app/core/auth'
import { BytesPipe } from '@app/shared/shared-main' import { BytesPipe } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserLocalStorageKeys } from '@root-helpers/users' import { UserLocalStorageKeys } from '@root-helpers/users'
import { import {
Avatar, Avatar,
@ -38,9 +37,8 @@ export class UserService {
private restExtractor: RestExtractor, private restExtractor: RestExtractor,
private restService: RestService, private restService: RestService,
private localStorageService: LocalStorageService, private localStorageService: LocalStorageService,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService
private i18n: I18n ) { }
) { }
changePassword (currentPassword: string, newPassword: string) { changePassword (currentPassword: string, newPassword: string) {
const url = UserService.BASE_USERS_URL + 'me' const url = UserService.BASE_USERS_URL + 'me'
@ -383,9 +381,9 @@ export class UserService {
} }
const roleLabels: { [ id in UserRole ]: string } = { const roleLabels: { [ id in UserRole ]: string } = {
[UserRole.USER]: this.i18n('User'), [UserRole.USER]: $localize`User`,
[UserRole.ADMINISTRATOR]: this.i18n('Administrator'), [UserRole.ADMINISTRATOR]: $localize`Administrator`,
[UserRole.MODERATOR]: this.i18n('Moderator') [UserRole.MODERATOR]: $localize`Moderator`
} }
return Object.assign(user, { return Object.assign(user, {

View File

@ -5,7 +5,6 @@ import { Component, OnInit, ViewChild } from '@angular/core'
import { AuthService, AuthStatus, AuthUser, RedirectService, ScreenService, ServerService, UserService } from '@app/core' import { AuthService, AuthStatus, AuthUser, RedirectService, ScreenService, ServerService, UserService } from '@app/core'
import { LanguageChooserComponent } from '@app/menu/language-chooser.component' import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component' import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig, UserRight, VideoConstant } from '@shared/models' import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
const logger = debug('peertube:menu:MenuComponent') const logger = debug('peertube:menu:MenuComponent')
@ -44,9 +43,8 @@ export class MenuComponent implements OnInit {
private serverService: ServerService, private serverService: ServerService,
private redirectService: RedirectService, private redirectService: RedirectService,
private hotkeysService: HotkeysService, private hotkeysService: HotkeysService,
private screenService: ScreenService, private screenService: ScreenService
private i18n: I18n ) { }
) { }
get isInMobileView () { get isInMobileView () {
return this.screenService.isInMobileView() return this.screenService.isInMobileView()
@ -117,13 +115,13 @@ export class MenuComponent implements OnInit {
switch (this.user.nsfwPolicy) { switch (this.user.nsfwPolicy) {
case 'do_not_list': case 'do_not_list':
return this.i18n('hide') return $localize`hide`
case 'blur': case 'blur':
return this.i18n('blur') return $localize`blur`
case 'display': case 'display':
return this.i18n('display') return $localize`display`
} }
} }
@ -189,7 +187,7 @@ export class MenuComponent implements OnInit {
} }
langForLocale (localeId: string) { langForLocale (localeId: string) {
if (localeId === '_unknown') return this.i18n('Unknown') if (localeId === '_unknown') return $localize`Unknown`
return this.languages.find(lang => lang.id === localeId).label return this.languages.find(lang => lang.id === localeId).label
} }
@ -201,7 +199,7 @@ export class MenuComponent implements OnInit {
} }
if (!this.user.videoLanguages) { if (!this.user.videoLanguages) {
this.videoLanguages = [this.i18n('any language')] this.videoLanguages = [$localize`any language`]
return return
} }

View File

@ -3,7 +3,6 @@ import { ConfirmService } from '@app/core/confirm/confirm.service'
import { POP_STATE_MODAL_DISMISS } from '@app/helpers' import { POP_STATE_MODAL_DISMISS } from '@app/helpers'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-confirm', selector: 'my-confirm',
@ -25,8 +24,7 @@ export class ConfirmComponent implements OnInit {
constructor ( constructor (
private modalService: NgbModal, private modalService: NgbModal,
private confirmService: ConfirmService, private confirmService: ConfirmService
private i18n: I18n
) { } ) { }
ngOnInit () { ngOnInit () {
@ -38,7 +36,7 @@ export class ConfirmComponent implements OnInit {
this.inputLabel = inputLabel this.inputLabel = inputLabel
this.expectedInputValue = expectedInputValue this.expectedInputValue = expectedInputValue
this.confirmButtonText = confirmButtonText || this.i18n('Confirm') this.confirmButtonText = confirmButtonText || $localize`Confirm`
this.showModal() this.showModal()
} }

View File

@ -1,7 +1,6 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { durationToString } from '@app/helpers' import { durationToString } from '@app/helpers'
import { Actor } from '@app/shared/shared-main' import { Actor } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AbusePredefinedReasonsString } from '@shared/models' import { AbusePredefinedReasonsString } from '@shared/models'
import { ProcessedAbuse } from './processed-abuse.model' import { ProcessedAbuse } from './processed-abuse.model'
@ -17,18 +16,16 @@ export class AbuseDetailsComponent {
private predefinedReasonsTranslations: { [key in AbusePredefinedReasonsString]: string } private predefinedReasonsTranslations: { [key in AbusePredefinedReasonsString]: string }
constructor ( constructor () {
private i18n: I18n
) {
this.predefinedReasonsTranslations = { this.predefinedReasonsTranslations = {
violentOrRepulsive: this.i18n('Violent or Repulsive'), violentOrRepulsive: $localize`Violent or Repulsive`,
hatefulOrAbusive: this.i18n('Hateful or Abusive'), hatefulOrAbusive: $localize`Hateful or Abusive`,
spamOrMisleading: this.i18n('Spam or Misleading'), spamOrMisleading: $localize`Spam or Misleading`,
privacy: this.i18n('Privacy'), privacy: $localize`Privacy`,
rights: this.i18n('Copyright'), rights: $localize`Copyright`,
serverRules: this.i18n('Server rules'), serverRules: $localize`Server rules`,
thumbnails: this.i18n('Thumbnails'), thumbnails: $localize`Thumbnails`,
captions: this.i18n('Captions') captions: $localize`Captions`
} }
} }

View File

@ -1,16 +1,15 @@
import * as debug from 'debug' import * as debug from 'debug'
import truncate from 'lodash-es/truncate' import truncate from 'lodash-es/truncate'
import { SortMeta } from 'primeng/api' import { SortMeta } from 'primeng/api'
import { buildVideoOrPlaylistEmbed, buildVideoLink } from 'src/assets/player/utils' import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
import { environment } from 'src/environments/environment' import { environment } from 'src/environments/environment'
import { AfterViewInit, Component, OnInit, ViewChild, Input } from '@angular/core' import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'
import { DomSanitizer } from '@angular/platform-browser' import { DomSanitizer } from '@angular/platform-browser'
import { ActivatedRoute, Params, Router } from '@angular/router' import { ActivatedRoute, Params, Router } from '@angular/router'
import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core'
import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main' import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main'
import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation'
import { VideoCommentService } from '@app/shared/shared-video-comment' import { VideoCommentService } from '@app/shared/shared-video-comment'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AbuseState, AdminAbuse } from '@shared/models' import { AbuseState, AdminAbuse } from '@shared/models'
import { AbuseMessageModalComponent } from './abuse-message-modal.component' import { AbuseMessageModalComponent } from './abuse-message-modal.component'
import { ModerationCommentModalComponent } from './moderation-comment-modal.component' import { ModerationCommentModalComponent } from './moderation-comment-modal.component'
@ -45,7 +44,6 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
private videoService: VideoService, private videoService: VideoService,
private videoBlocklistService: VideoBlockService, private videoBlocklistService: VideoBlockService,
private confirmService: ConfirmService, private confirmService: ConfirmService,
private i18n: I18n,
private markdownRenderer: MarkdownService, private markdownRenderer: MarkdownService,
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private route: ActivatedRoute, private route: ActivatedRoute,
@ -157,12 +155,12 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
} }
async removeAbuse (abuse: AdminAbuse) { async removeAbuse (abuse: AdminAbuse) {
const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse report?'), this.i18n('Delete')) const res = await this.confirmService.confirm($localize`Do you really want to delete this abuse report?`, $localize`Delete`)
if (res === false) return if (res === false) return
this.abuseService.removeAbuse(abuse).subscribe( this.abuseService.removeAbuse(abuse).subscribe(
() => { () => {
this.notifier.success(this.i18n('Abuse deleted.')) this.notifier.success($localize`Abuse deleted.`)
this.loadData() this.loadData()
}, },
@ -238,7 +236,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
if (abuse.comment) { if (abuse.comment) {
if (abuse.comment.deleted) { if (abuse.comment.deleted) {
abuse.truncatedCommentHtml = abuse.commentHtml = this.i18n('Deleted comment') abuse.truncatedCommentHtml = abuse.commentHtml = $localize`Deleted comment`
} else { } else {
const truncated = truncate(abuse.comment.text, { length: 100 }) const truncated = truncate(abuse.comment.text, { length: 100 })
abuse.truncatedCommentHtml = await this.markdownRenderer.textMarkdownToHTML(truncated, true) abuse.truncatedCommentHtml = await this.markdownRenderer.textMarkdownToHTML(truncated, true)
@ -267,38 +265,38 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
private buildInternalActions (): DropdownAction<ProcessedAbuse>[] { private buildInternalActions (): DropdownAction<ProcessedAbuse>[] {
return [ return [
{ {
label: this.i18n('Internal actions'), label: $localize`Internal actions`,
isHeader: true isHeader: true
}, },
{ {
label: this.isAdminView() label: this.isAdminView()
? this.i18n('Messages with reporter') ? $localize`Messages with reporter`
: this.i18n('Messages with moderators'), : $localize`Messages with moderators`,
handler: abuse => this.openAbuseMessagesModal(abuse), handler: abuse => this.openAbuseMessagesModal(abuse),
isDisplayed: abuse => this.isLocalAbuse(abuse) isDisplayed: abuse => this.isLocalAbuse(abuse)
}, },
{ {
label: this.i18n('Update internal note'), label: $localize`Update internal note`,
handler: abuse => this.openModerationCommentModal(abuse), handler: abuse => this.openModerationCommentModal(abuse),
isDisplayed: abuse => this.isAdminView() && !!abuse.moderationComment isDisplayed: abuse => this.isAdminView() && !!abuse.moderationComment
}, },
{ {
label: this.i18n('Mark as accepted'), label: $localize`Mark as accepted`,
handler: abuse => this.updateAbuseState(abuse, AbuseState.ACCEPTED), handler: abuse => this.updateAbuseState(abuse, AbuseState.ACCEPTED),
isDisplayed: abuse => this.isAdminView() && !this.isAbuseAccepted(abuse) isDisplayed: abuse => this.isAdminView() && !this.isAbuseAccepted(abuse)
}, },
{ {
label: this.i18n('Mark as rejected'), label: $localize`Mark as rejected`,
handler: abuse => this.updateAbuseState(abuse, AbuseState.REJECTED), handler: abuse => this.updateAbuseState(abuse, AbuseState.REJECTED),
isDisplayed: abuse => this.isAdminView() && !this.isAbuseRejected(abuse) isDisplayed: abuse => this.isAdminView() && !this.isAbuseRejected(abuse)
}, },
{ {
label: this.i18n('Add internal note'), label: $localize`Add internal note`,
handler: abuse => this.openModerationCommentModal(abuse), handler: abuse => this.openModerationCommentModal(abuse),
isDisplayed: abuse => this.isAdminView() && !abuse.moderationComment isDisplayed: abuse => this.isAdminView() && !abuse.moderationComment
}, },
{ {
label: this.i18n('Delete report'), label: $localize`Delete report`,
handler: abuse => this.isAdminView() && this.removeAbuse(abuse) handler: abuse => this.isAdminView() && this.removeAbuse(abuse)
} }
] ]
@ -309,19 +307,19 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
return [ return [
{ {
label: this.i18n('Actions for the flagged account'), label: $localize`Actions for the flagged account`,
isHeader: true, isHeader: true,
isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video
}, },
{ {
label: this.i18n('Mute account'), label: $localize`Mute account`,
isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video, isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video,
handler: abuse => this.muteAccountHelper(abuse.flaggedAccount) handler: abuse => this.muteAccountHelper(abuse.flaggedAccount)
}, },
{ {
label: this.i18n('Mute server account'), label: $localize`Mute server account`,
isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video, isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video,
handler: abuse => this.muteServerHelper(abuse.flaggedAccount.host) handler: abuse => this.muteServerHelper(abuse.flaggedAccount.host)
} }
@ -333,19 +331,19 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
return [ return [
{ {
label: this.i18n('Actions for the reporter'), label: $localize`Actions for the reporter`,
isHeader: true, isHeader: true,
isDisplayed: abuse => !!abuse.reporterAccount isDisplayed: abuse => !!abuse.reporterAccount
}, },
{ {
label: this.i18n('Mute reporter'), label: $localize`Mute reporter`,
isDisplayed: abuse => !!abuse.reporterAccount, isDisplayed: abuse => !!abuse.reporterAccount,
handler: abuse => this.muteAccountHelper(abuse.reporterAccount) handler: abuse => this.muteAccountHelper(abuse.reporterAccount)
}, },
{ {
label: this.i18n('Mute server'), label: $localize`Mute server`,
isDisplayed: abuse => abuse.reporterAccount && !abuse.reporterAccount.userId, isDisplayed: abuse => abuse.reporterAccount && !abuse.reporterAccount.userId,
handler: abuse => this.muteServerHelper(abuse.reporterAccount.host) handler: abuse => this.muteServerHelper(abuse.reporterAccount.host)
} }
@ -357,18 +355,18 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
return [ return [
{ {
label: this.i18n('Actions for the video'), label: $localize`Actions for the video`,
isHeader: true, isHeader: true,
isDisplayed: abuse => abuse.video && !abuse.video.deleted isDisplayed: abuse => abuse.video && !abuse.video.deleted
}, },
{ {
label: this.i18n('Block video'), label: $localize`Block video`,
isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted, isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted,
handler: abuse => { handler: abuse => {
this.videoBlocklistService.blockVideo(abuse.video.id, undefined, true) this.videoBlocklistService.blockVideo(abuse.video.id, undefined, true)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Video blocked.')) this.notifier.success($localize`Video blocked.`)
this.updateAbuseState(abuse, AbuseState.ACCEPTED) this.updateAbuseState(abuse, AbuseState.ACCEPTED)
}, },
@ -378,13 +376,13 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
} }
}, },
{ {
label: this.i18n('Unblock video'), label: $localize`Unblock video`,
isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted, isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted,
handler: abuse => { handler: abuse => {
this.videoBlocklistService.unblockVideo(abuse.video.id) this.videoBlocklistService.unblockVideo(abuse.video.id)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Video unblocked.')) this.notifier.success($localize`Video unblocked.`)
this.updateAbuseState(abuse, AbuseState.ACCEPTED) this.updateAbuseState(abuse, AbuseState.ACCEPTED)
}, },
@ -394,19 +392,19 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
} }
}, },
{ {
label: this.i18n('Delete video'), label: $localize`Delete video`,
isDisplayed: abuse => abuse.video && !abuse.video.deleted, isDisplayed: abuse => abuse.video && !abuse.video.deleted,
handler: async abuse => { handler: async abuse => {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to delete this video?'), $localize`Do you really want to delete this video?`,
this.i18n('Delete') $localize`Delete`
) )
if (res === false) return if (res === false) return
this.videoService.removeVideo(abuse.video.id) this.videoService.removeVideo(abuse.video.id)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Video deleted.')) this.notifier.success($localize`Video deleted.`)
this.updateAbuseState(abuse, AbuseState.ACCEPTED) this.updateAbuseState(abuse, AbuseState.ACCEPTED)
}, },
@ -423,25 +421,25 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
return [ return [
{ {
label: this.i18n('Actions for the comment'), label: $localize`Actions for the comment`,
isHeader: true, isHeader: true,
isDisplayed: abuse => abuse.comment && !abuse.comment.deleted isDisplayed: abuse => abuse.comment && !abuse.comment.deleted
}, },
{ {
label: this.i18n('Delete comment'), label: $localize`Delete comment`,
isDisplayed: abuse => abuse.comment && !abuse.comment.deleted, isDisplayed: abuse => abuse.comment && !abuse.comment.deleted,
handler: async abuse => { handler: async abuse => {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
this.i18n('Do you really want to delete this comment?'), $localize`Do you really want to delete this comment?`,
this.i18n('Delete') $localize`Delete`
) )
if (res === false) return if (res === false) return
this.commentService.deleteVideoComment(abuse.comment.video.id, abuse.comment.id) this.commentService.deleteVideoComment(abuse.comment.video.id, abuse.comment.id)
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Comment deleted.')) this.notifier.success($localize`Comment deleted.`)
this.updateAbuseState(abuse, AbuseState.ACCEPTED) this.updateAbuseState(abuse, AbuseState.ACCEPTED)
}, },
@ -457,10 +455,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
this.blocklistService.blockAccountByInstance(account) this.blocklistService.blockAccountByInstance(account)
.subscribe( .subscribe(
() => { () => {
this.notifier.success( this.notifier.success($localize`Account ${account.nameWithHost} muted by the instance.`)
this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost })
)
account.mutedByInstance = true account.mutedByInstance = true
}, },
@ -472,9 +467,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
this.blocklistService.blockServerByInstance(host) this.blocklistService.blockServerByInstance(host)
.subscribe( .subscribe(
() => { () => {
this.notifier.success( this.notifier.success($localize`Server ${host} muted by the instance.`)
this.i18n('Server {{host}} muted by the instance.', { host: host })
)
}, },
err => this.notifier.error(err.message) err => this.notifier.error(err.message)

View File

@ -1,9 +1,8 @@
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
import { AuthService, Notifier, HtmlRendererService } from '@app/core' import { AuthService, HtmlRendererService, Notifier } from '@app/core'
import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AbuseMessage, UserAbuse } from '@shared/models' import { AbuseMessage, UserAbuse } from '@shared/models'
import { AbuseService } from '../shared-moderation' import { AbuseService } from '../shared-moderation'
@ -31,7 +30,6 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
protected formValidatorService: FormValidatorService, protected formValidatorService: FormValidatorService,
private abuseValidatorsService: AbuseValidatorsService, private abuseValidatorsService: AbuseValidatorsService,
private modalService: NgbModal, private modalService: NgbModal,
private i18n: I18n,
private htmlRenderer: HtmlRendererService, private htmlRenderer: HtmlRendererService,
private auth: AuthService, private auth: AuthService,
private notifier: Notifier, private notifier: Notifier,
@ -99,10 +97,10 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
getPlaceholderMessage () { getPlaceholderMessage () {
if (this.isAdminView) { if (this.isAdminView) {
return this.i18n('Add a message to communicate with the reporter') return $localize`Add a message to communicate with the reporter`
} }
return this.i18n('Add a message to communicate with the moderation team') return $localize`Add a message to communicate with the moderation team`
} }
private loadMessages () { private loadMessages () {

View File

@ -1,10 +1,9 @@
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
import { Notifier } from '@app/core' import { Notifier } from '@app/core'
import { FormReactive, FormValidatorService, AbuseValidatorsService } from '@app/shared/shared-forms' import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { AbuseService } from '@app/shared/shared-moderation' import { AbuseService } from '@app/shared/shared-moderation'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AdminAbuse } from '@shared/models' import { AdminAbuse } from '@shared/models'
@Component({ @Component({
@ -24,8 +23,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
private modalService: NgbModal, private modalService: NgbModal,
private notifier: Notifier, private notifier: Notifier,
private abuseService: AbuseService, private abuseService: AbuseService,
private abuseValidatorsService: AbuseValidatorsService, private abuseValidatorsService: AbuseValidatorsService
private i18n: I18n
) { ) {
super() super()
} }
@ -57,7 +55,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
this.abuseService.updateAbuse(this.abuseToComment, { moderationComment }) this.abuseService.updateAbuse(this.abuseToComment, { moderationComment })
.subscribe( .subscribe(
() => { () => {
this.notifier.success(this.i18n('Comment updated.')) this.notifier.success($localize`Comment updated.`)
this.commentUpdated.emit(moderationComment) this.commentUpdated.emit(moderationComment)
this.hide() this.hide()

View File

@ -1,6 +1,5 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
@ -9,31 +8,31 @@ export class AbuseValidatorsService {
readonly ABUSE_MODERATION_COMMENT: BuildFormValidator readonly ABUSE_MODERATION_COMMENT: BuildFormValidator
readonly ABUSE_MESSAGE: BuildFormValidator readonly ABUSE_MESSAGE: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.ABUSE_REASON = { this.ABUSE_REASON = {
VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ], VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Report reason is required.'), 'required': $localize`Report reason is required.`,
'minlength': this.i18n('Report reason must be at least 2 characters long.'), 'minlength': $localize`Report reason must be at least 2 characters long.`,
'maxlength': this.i18n('Report reason cannot be more than 3000 characters long.') 'maxlength': $localize`Report reason cannot be more than 3000 characters long.`
} }
} }
this.ABUSE_MODERATION_COMMENT = { this.ABUSE_MODERATION_COMMENT = {
VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ], VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Moderation comment is required.'), 'required': $localize`Moderation comment is required.`,
'minlength': this.i18n('Moderation comment must be at least 2 characters long.'), 'minlength': $localize`Moderation comment must be at least 2 characters long.`,
'maxlength': this.i18n('Moderation comment cannot be more than 3000 characters long.') 'maxlength': $localize`Moderation comment cannot be more than 3000 characters long.`
} }
} }
this.ABUSE_MESSAGE = { this.ABUSE_MESSAGE = {
VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ], VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Abuse message is required.'), 'required': $localize`Abuse message is required.`,
'minlength': this.i18n('Abuse message must be at least 2 characters long.'), 'minlength': $localize`Abuse message must be at least 2 characters long.`,
'maxlength': this.i18n('Abuse message cannot be more than 3000 characters long.') 'maxlength': $localize`Abuse message cannot be more than 3000 characters long.`
} }
} }
} }

View File

@ -1,6 +1,5 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { ValidatorFn, Validators } from '@angular/forms' import { ValidatorFn, Validators } from '@angular/forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
import { validateHost } from './host' import { validateHost } from './host'
@ -8,13 +7,13 @@ import { validateHost } from './host'
export class BatchDomainsValidatorsService { export class BatchDomainsValidatorsService {
readonly DOMAINS: BuildFormValidator readonly DOMAINS: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.DOMAINS = { this.DOMAINS = {
VALIDATORS: [ Validators.required, this.validDomains, this.isHostsUnique ], VALIDATORS: [ Validators.required, this.validDomains, this.isHostsUnique ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Domain is required.'), 'required': $localize`Domain is required.`,
'validDomains': this.i18n('Domains entered are invalid.'), 'validDomains': $localize`Domains entered are invalid.`,
'uniqueDomains': this.i18n('Domains entered contain duplicates.') 'uniqueDomains': $localize`Domains entered contain duplicates.`
} }
} }
} }
@ -33,7 +32,7 @@ export class BatchDomainsValidatorsService {
for (const host of hosts) { for (const host of hosts) {
if (validateHost(host) === false) { if (validateHost(host) === false) {
newHostsErrors.push(this.i18n('{{host}} is not valid', { host })) newHostsErrors.push($localize`${host} is not valid`)
} }
} }

View File

@ -1,7 +1,6 @@
import { Validators } from '@angular/forms'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { BuildFormValidator } from './form-validator.service'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class CustomConfigValidatorsService { export class CustomConfigValidatorsService {
@ -16,82 +15,82 @@ export class CustomConfigValidatorsService {
readonly INDEX_URL: BuildFormValidator readonly INDEX_URL: BuildFormValidator
readonly SEARCH_INDEX_URL: BuildFormValidator readonly SEARCH_INDEX_URL: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.INSTANCE_NAME = { this.INSTANCE_NAME = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Instance name is required.') 'required': $localize`Instance name is required.`
} }
} }
this.INSTANCE_SHORT_DESCRIPTION = { this.INSTANCE_SHORT_DESCRIPTION = {
VALIDATORS: [ Validators.max(250) ], VALIDATORS: [ Validators.max(250) ],
MESSAGES: { MESSAGES: {
'max': this.i18n('Short description should not be longer than 250 characters.') 'max': $localize`Short description should not be longer than 250 characters.`
} }
} }
this.SERVICES_TWITTER_USERNAME = { this.SERVICES_TWITTER_USERNAME = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Twitter username is required.') 'required': $localize`Twitter username is required.`
} }
} }
this.CACHE_PREVIEWS_SIZE = { this.CACHE_PREVIEWS_SIZE = {
VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ], VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Previews cache size is required.'), 'required': $localize`Previews cache size is required.`,
'min': this.i18n('Previews cache size must be greater than 1.'), 'min': $localize`Previews cache size must be greater than 1.`,
'pattern': this.i18n('Previews cache size must be a number.') 'pattern': $localize`Previews cache size must be a number.`
} }
} }
this.CACHE_CAPTIONS_SIZE = { this.CACHE_CAPTIONS_SIZE = {
VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ], VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Captions cache size is required.'), 'required': $localize`Captions cache size is required.`,
'min': this.i18n('Captions cache size must be greater than 1.'), 'min': $localize`Captions cache size must be greater than 1.`,
'pattern': this.i18n('Captions cache size must be a number.') 'pattern': $localize`Captions cache size must be a number.`
} }
} }
this.SIGNUP_LIMIT = { this.SIGNUP_LIMIT = {
VALIDATORS: [ Validators.required, Validators.min(-1), Validators.pattern('-?[0-9]+') ], VALIDATORS: [ Validators.required, Validators.min(-1), Validators.pattern('-?[0-9]+') ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Signup limit is required.'), 'required': $localize`Signup limit is required.`,
'min': this.i18n('Signup limit must be greater than 1.'), 'min': $localize`Signup limit must be greater than 1.`,
'pattern': this.i18n('Signup limit must be a number.') 'pattern': $localize`Signup limit must be a number.`
} }
} }
this.ADMIN_EMAIL = { this.ADMIN_EMAIL = {
VALIDATORS: [ Validators.required, Validators.email ], VALIDATORS: [ Validators.required, Validators.email ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Admin email is required.'), 'required': $localize`Admin email is required.`,
'email': this.i18n('Admin email must be valid.') 'email': $localize`Admin email must be valid.`
} }
} }
this.TRANSCODING_THREADS = { this.TRANSCODING_THREADS = {
VALIDATORS: [ Validators.required, Validators.min(0) ], VALIDATORS: [ Validators.required, Validators.min(0) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Transcoding threads is required.'), 'required': $localize`Transcoding threads is required.`,
'min': this.i18n('Transcoding threads must be greater or equal to 0.') 'min': $localize`Transcoding threads must be greater or equal to 0.`
} }
} }
this.INDEX_URL = { this.INDEX_URL = {
VALIDATORS: [ Validators.pattern(/^https:\/\//) ], VALIDATORS: [ Validators.pattern(/^https:\/\//) ],
MESSAGES: { MESSAGES: {
'pattern': this.i18n('Index URL should be a URL') 'pattern': $localize`Index URL should be a URL`
} }
} }
this.SEARCH_INDEX_URL = { this.SEARCH_INDEX_URL = {
VALIDATORS: [ Validators.pattern(/^https?:\/\//) ], VALIDATORS: [ Validators.pattern(/^https?:\/\//) ],
MESSAGES: { MESSAGES: {
'pattern': this.i18n('Search index URL should be a URL') 'pattern': $localize`Search index URL should be a URL`
} }
} }
} }

View File

@ -1,7 +1,6 @@
import { I18n } from '@ngx-translate/i18n-polyfill' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms' import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
import { Injectable } from '@angular/core'
@Injectable() @Injectable()
export class InstanceValidatorsService { export class InstanceValidatorsService {
@ -10,13 +9,13 @@ export class InstanceValidatorsService {
readonly SUBJECT: BuildFormValidator readonly SUBJECT: BuildFormValidator
readonly BODY: BuildFormValidator readonly BODY: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.FROM_EMAIL = { this.FROM_EMAIL = {
VALIDATORS: [ Validators.required, Validators.email ], VALIDATORS: [ Validators.required, Validators.email ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Email is required.'), 'required': $localize`Email is required.`,
'email': this.i18n('Email must be valid.') 'email': $localize`Email must be valid.`
} }
} }
@ -27,9 +26,9 @@ export class InstanceValidatorsService {
Validators.maxLength(120) Validators.maxLength(120)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Your name is required.'), 'required': $localize`Your name is required.`,
'minlength': this.i18n('Your name must be at least 1 character long.'), 'minlength': $localize`Your name must be at least 1 character long.`,
'maxlength': this.i18n('Your name cannot be more than 120 characters long.') 'maxlength': $localize`Your name cannot be more than 120 characters long.`
} }
} }
@ -40,9 +39,9 @@ export class InstanceValidatorsService {
Validators.maxLength(120) Validators.maxLength(120)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('A subject is required.'), 'required': $localize`A subject is required.`,
'minlength': this.i18n('The subject must be at least 1 character long.'), 'minlength': $localize`The subject must be at least 1 character long.`,
'maxlength': this.i18n('The subject cannot be more than 120 characters long.') 'maxlength': $localize`The subject cannot be more than 120 characters long.`
} }
} }
@ -53,9 +52,9 @@ export class InstanceValidatorsService {
Validators.maxLength(5000) Validators.maxLength(5000)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('A message is required.'), 'required': $localize`A message is required.`,
'minlength': this.i18n('The message must be at least 3 characters long.'), 'minlength': $localize`The message must be at least 3 characters long.`,
'maxlength': this.i18n('The message cannot be more than 5000 characters long.') 'maxlength': $localize`The message cannot be more than 5000 characters long.`
} }
} }
} }

View File

@ -1,6 +1,5 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
@ -8,13 +7,13 @@ export class LoginValidatorsService {
readonly LOGIN_USERNAME: BuildFormValidator readonly LOGIN_USERNAME: BuildFormValidator
readonly LOGIN_PASSWORD: BuildFormValidator readonly LOGIN_PASSWORD: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.LOGIN_USERNAME = { this.LOGIN_USERNAME = {
VALIDATORS: [ VALIDATORS: [
Validators.required Validators.required
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Username is required.') 'required': $localize`Username is required.`
} }
} }
@ -23,7 +22,7 @@ export class LoginValidatorsService {
Validators.required Validators.required
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Password is required.') 'required': $localize`Password is required.`
} }
} }
} }

View File

@ -1,19 +1,18 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class ResetPasswordValidatorsService { export class ResetPasswordValidatorsService {
readonly RESET_PASSWORD_CONFIRM: BuildFormValidator readonly RESET_PASSWORD_CONFIRM: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.RESET_PASSWORD_CONFIRM = { this.RESET_PASSWORD_CONFIRM = {
VALIDATORS: [ VALIDATORS: [
Validators.required Validators.required
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Confirmation of the password is required.') 'required': $localize`Confirmation of the password is required.`
} }
} }
} }

View File

@ -1,7 +1,6 @@
import { I18n } from '@ngx-translate/i18n-polyfill' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms' import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
import { Injectable } from '@angular/core'
@Injectable() @Injectable()
export class UserValidatorsService { export class UserValidatorsService {
@ -20,7 +19,7 @@ export class UserValidatorsService {
readonly USER_BAN_REASON: BuildFormValidator readonly USER_BAN_REASON: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.USER_USERNAME = { this.USER_USERNAME = {
VALIDATORS: [ VALIDATORS: [
@ -30,10 +29,10 @@ export class UserValidatorsService {
Validators.pattern(/^[a-z0-9][a-z0-9._]*$/) Validators.pattern(/^[a-z0-9][a-z0-9._]*$/)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Username is required.'), 'required': $localize`Username is required.`,
'minlength': this.i18n('Username must be at least 1 character long.'), 'minlength': $localize`Username must be at least 1 character long.`,
'maxlength': this.i18n('Username cannot be more than 50 characters long.'), 'maxlength': $localize`Username cannot be more than 50 characters long.`,
'pattern': this.i18n('Username should be lowercase alphanumeric; dots and underscores are allowed.') 'pattern': $localize`Username should be lowercase alphanumeric; dots and underscores are allowed.`
} }
} }
@ -45,18 +44,18 @@ export class UserValidatorsService {
Validators.pattern(/^[a-z0-9][a-z0-9._]*$/) Validators.pattern(/^[a-z0-9][a-z0-9._]*$/)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Channel name is required.'), 'required': $localize`Channel name is required.`,
'minlength': this.i18n('Channel name must be at least 1 character long.'), 'minlength': $localize`Channel name must be at least 1 character long.`,
'maxlength': this.i18n('Channel name cannot be more than 50 characters long.'), 'maxlength': $localize`Channel name cannot be more than 50 characters long.`,
'pattern': this.i18n('Channel name should be lowercase alphanumeric; dots and underscores are allowed.') 'pattern': $localize`Channel name should be lowercase alphanumeric; dots and underscores are allowed.`
} }
} }
this.USER_EMAIL = { this.USER_EMAIL = {
VALIDATORS: [ Validators.required, Validators.email ], VALIDATORS: [ Validators.required, Validators.email ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Email is required.'), 'required': $localize`Email is required.`,
'email': this.i18n('Email must be valid.') 'email': $localize`Email must be valid.`
} }
} }
@ -67,9 +66,9 @@ export class UserValidatorsService {
Validators.maxLength(255) Validators.maxLength(255)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Password is required.'), 'required': $localize`Password is required.`,
'minlength': this.i18n('Password must be at least 6 characters long.'), 'minlength': $localize`Password must be at least 6 characters long.`,
'maxlength': this.i18n('Password cannot be more than 255 characters long.') 'maxlength': $localize`Password cannot be more than 255 characters long.`
} }
} }
@ -79,37 +78,37 @@ export class UserValidatorsService {
Validators.maxLength(255) Validators.maxLength(255)
], ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('Password must be at least 6 characters long.'), 'minlength': $localize`Password must be at least 6 characters long.`,
'maxlength': this.i18n('Password cannot be more than 255 characters long.') 'maxlength': $localize`Password cannot be more than 255 characters long.`
} }
} }
this.USER_CONFIRM_PASSWORD = { this.USER_CONFIRM_PASSWORD = {
VALIDATORS: [], VALIDATORS: [],
MESSAGES: { MESSAGES: {
'matchPassword': this.i18n('The new password and the confirmed password do not correspond.') 'matchPassword': $localize`The new password and the confirmed password do not correspond.`
} }
} }
this.USER_VIDEO_QUOTA = { this.USER_VIDEO_QUOTA = {
VALIDATORS: [ Validators.required, Validators.min(-1) ], VALIDATORS: [ Validators.required, Validators.min(-1) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Video quota is required.'), 'required': $localize`Video quota is required.`,
'min': this.i18n('Quota must be greater than -1.') 'min': $localize`Quota must be greater than -1.`
} }
} }
this.USER_VIDEO_QUOTA_DAILY = { this.USER_VIDEO_QUOTA_DAILY = {
VALIDATORS: [ Validators.required, Validators.min(-1) ], VALIDATORS: [ Validators.required, Validators.min(-1) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Daily upload limit is required.'), 'required': $localize`Daily upload limit is required.`,
'min': this.i18n('Daily upload limit must be greater than -1.') 'min': $localize`Daily upload limit must be greater than -1.`
} }
} }
this.USER_ROLE = { this.USER_ROLE = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('User role is required.') 'required': $localize`User role is required.`
} }
} }
@ -121,8 +120,8 @@ export class UserValidatorsService {
Validators.maxLength(1000) Validators.maxLength(1000)
], ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('Description must be at least 3 characters long.'), 'minlength': $localize`Description must be at least 3 characters long.`,
'maxlength': this.i18n('Description cannot be more than 1000 characters long.') 'maxlength': $localize`Description cannot be more than 1000 characters long.`
} }
} }
@ -131,7 +130,7 @@ export class UserValidatorsService {
Validators.requiredTrue Validators.requiredTrue
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('You must agree with the instance terms in order to register on it.') 'required': $localize`You must agree with the instance terms in order to register on it.`
} }
} }
@ -141,8 +140,8 @@ export class UserValidatorsService {
Validators.maxLength(250) Validators.maxLength(250)
], ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('Ban reason must be at least 3 characters long.'), 'minlength': $localize`Ban reason must be at least 3 characters long.`,
'maxlength': this.i18n('Ban reason cannot be more than 250 characters long.') 'maxlength': $localize`Ban reason cannot be more than 250 characters long.`
} }
} }
} }
@ -154,9 +153,9 @@ export class UserValidatorsService {
Validators.maxLength(120) Validators.maxLength(120)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Display name is required.'), 'required': $localize`Display name is required.`,
'minlength': this.i18n('Display name must be at least 1 character long.'), 'minlength': $localize`Display name must be at least 1 character long.`,
'maxlength': this.i18n('Display name cannot be more than 50 characters long.') 'maxlength': $localize`Display name cannot be more than 50 characters long.`
} }
} }

View File

@ -1,17 +1,16 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class VideoAcceptOwnershipValidatorsService { export class VideoAcceptOwnershipValidatorsService {
readonly CHANNEL: BuildFormValidator readonly CHANNEL: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.CHANNEL = { this.CHANNEL = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('The channel is required.') 'required': $localize`The channel is required.`
} }
} }
} }

View File

@ -1,18 +1,17 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class VideoBlockValidatorsService { export class VideoBlockValidatorsService {
readonly VIDEO_BLOCK_REASON: BuildFormValidator readonly VIDEO_BLOCK_REASON: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.VIDEO_BLOCK_REASON = { this.VIDEO_BLOCK_REASON = {
VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ], VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('Block reason must be at least 2 characters long.'), 'minlength': $localize`Block reason must be at least 2 characters long.`,
'maxlength': this.i18n('Block reason cannot be more than 300 characters long.') 'maxlength': $localize`Block reason cannot be more than 300 characters long.`
} }
} }
} }

View File

@ -1,6 +1,5 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
@ -8,19 +7,19 @@ export class VideoCaptionsValidatorsService {
readonly VIDEO_CAPTION_LANGUAGE: BuildFormValidator readonly VIDEO_CAPTION_LANGUAGE: BuildFormValidator
readonly VIDEO_CAPTION_FILE: BuildFormValidator readonly VIDEO_CAPTION_FILE: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.VIDEO_CAPTION_LANGUAGE = { this.VIDEO_CAPTION_LANGUAGE = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Video caption language is required.') 'required': $localize`Video caption language is required.`
} }
} }
this.VIDEO_CAPTION_FILE = { this.VIDEO_CAPTION_FILE = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Video caption file is required.') 'required': $localize`Video caption file is required.`
} }
} }
} }

View File

@ -1,18 +1,17 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AbstractControl, ValidationErrors, Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { AbstractControl, ValidationErrors, Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class VideoChangeOwnershipValidatorsService { export class VideoChangeOwnershipValidatorsService {
readonly USERNAME: BuildFormValidator readonly USERNAME: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.USERNAME = { this.USERNAME = {
VALIDATORS: [ Validators.required, this.localAccountValidator ], VALIDATORS: [ Validators.required, this.localAccountValidator ],
MESSAGES: { MESSAGES: {
'required': this.i18n('The username is required.'), 'required': $localize`The username is required.`,
'localAccountOnly': this.i18n('You can only transfer ownership to a local account') 'localAccountOnly': $localize`You can only transfer ownership to a local account`
} }
} }
} }

View File

@ -1,6 +1,5 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
@ -10,7 +9,7 @@ export class VideoChannelValidatorsService {
readonly VIDEO_CHANNEL_DESCRIPTION: BuildFormValidator readonly VIDEO_CHANNEL_DESCRIPTION: BuildFormValidator
readonly VIDEO_CHANNEL_SUPPORT: BuildFormValidator readonly VIDEO_CHANNEL_SUPPORT: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.VIDEO_CHANNEL_NAME = { this.VIDEO_CHANNEL_NAME = {
VALIDATORS: [ VALIDATORS: [
Validators.required, Validators.required,
@ -19,10 +18,10 @@ export class VideoChannelValidatorsService {
Validators.pattern(/^[a-z0-9][a-z0-9._]*$/) Validators.pattern(/^[a-z0-9][a-z0-9._]*$/)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Name is required.'), 'required': $localize`Name is required.`,
'minlength': this.i18n('Name must be at least 1 character long.'), 'minlength': $localize`Name must be at least 1 character long.`,
'maxlength': this.i18n('Name cannot be more than 50 characters long.'), 'maxlength': $localize`Name cannot be more than 50 characters long.`,
'pattern': this.i18n('Name should be lowercase alphanumeric; dots and underscores are allowed.') 'pattern': $localize`Name should be lowercase alphanumeric; dots and underscores are allowed.`
} }
} }
@ -33,9 +32,9 @@ export class VideoChannelValidatorsService {
Validators.maxLength(50) Validators.maxLength(50)
], ],
MESSAGES: { MESSAGES: {
'required': i18n('Display name is required.'), 'required': $localize`Display name is required.`,
'minlength': i18n('Display name must be at least 1 character long.'), 'minlength': $localize`Display name must be at least 1 character long.`,
'maxlength': i18n('Display name cannot be more than 50 characters long.') 'maxlength': $localize`Display name cannot be more than 50 characters long.`
} }
} }
@ -45,8 +44,8 @@ export class VideoChannelValidatorsService {
Validators.maxLength(1000) Validators.maxLength(1000)
], ],
MESSAGES: { MESSAGES: {
'minlength': i18n('Description must be at least 3 characters long.'), 'minlength': $localize`Description must be at least 3 characters long.`,
'maxlength': i18n('Description cannot be more than 1000 characters long.') 'maxlength': $localize`Description cannot be more than 1000 characters long.`
} }
} }
@ -56,8 +55,8 @@ export class VideoChannelValidatorsService {
Validators.maxLength(1000) Validators.maxLength(1000)
], ],
MESSAGES: { MESSAGES: {
'minlength': i18n('Support text must be at least 3 characters long.'), 'minlength': $localize`Support text must be at least 3 characters long.`,
'maxlength': i18n('Support text cannot be more than 1000 characters long.') 'maxlength': $localize`Support text cannot be more than 1000 characters long`
} }
} }
} }

View File

@ -1,19 +1,18 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class VideoCommentValidatorsService { export class VideoCommentValidatorsService {
readonly VIDEO_COMMENT_TEXT: BuildFormValidator readonly VIDEO_COMMENT_TEXT: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.VIDEO_COMMENT_TEXT = { this.VIDEO_COMMENT_TEXT = {
VALIDATORS: [ Validators.required, Validators.minLength(1), Validators.maxLength(3000) ], VALIDATORS: [ Validators.required, Validators.minLength(1), Validators.maxLength(3000) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Comment is required.'), 'required': $localize`Comment is required.`,
'minlength': this.i18n('Comment must be at least 2 characters long.'), 'minlength': $localize`Comment must be at least 2 characters long.`,
'maxlength': this.i18n('Comment cannot be more than 3000 characters long.') 'maxlength': $localize`Comment cannot be more than 3000 characters long.`
} }
} }
} }

View File

@ -1,8 +1,7 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AbstractControl, FormControl, Validators } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { BuildFormValidator } from './form-validator.service' import { AbstractControl, Validators } from '@angular/forms'
import { VideoPlaylistPrivacy } from '@shared/models' import { VideoPlaylistPrivacy } from '@shared/models'
import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
export class VideoPlaylistValidatorsService { export class VideoPlaylistValidatorsService {
@ -11,7 +10,7 @@ export class VideoPlaylistValidatorsService {
readonly VIDEO_PLAYLIST_DESCRIPTION: BuildFormValidator readonly VIDEO_PLAYLIST_DESCRIPTION: BuildFormValidator
readonly VIDEO_PLAYLIST_CHANNEL_ID: BuildFormValidator readonly VIDEO_PLAYLIST_CHANNEL_ID: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.VIDEO_PLAYLIST_DISPLAY_NAME = { this.VIDEO_PLAYLIST_DISPLAY_NAME = {
VALIDATORS: [ VALIDATORS: [
Validators.required, Validators.required,
@ -19,9 +18,9 @@ export class VideoPlaylistValidatorsService {
Validators.maxLength(120) Validators.maxLength(120)
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Display name is required.'), 'required': $localize`Display name is required.`,
'minlength': this.i18n('Display name must be at least 1 character long.'), 'minlength': $localize`Display name must be at least 1 character long.`,
'maxlength': this.i18n('Display name cannot be more than 120 characters long.') 'maxlength': $localize`Display name cannot be more than 120 characters long.`
} }
} }
@ -30,7 +29,7 @@ export class VideoPlaylistValidatorsService {
Validators.required Validators.required
], ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Privacy is required.') 'required': $localize`Privacy is required.`
} }
} }
@ -40,15 +39,15 @@ export class VideoPlaylistValidatorsService {
Validators.maxLength(1000) Validators.maxLength(1000)
], ],
MESSAGES: { MESSAGES: {
'minlength': i18n('Description must be at least 3 characters long.'), 'minlength': $localize`Description must be at least 3 characters long.`,
'maxlength': i18n('Description cannot be more than 1000 characters long.') 'maxlength': $localize`Description cannot be more than 1000 characters long.`
} }
} }
this.VIDEO_PLAYLIST_CHANNEL_ID = { this.VIDEO_PLAYLIST_CHANNEL_ID = {
VALIDATORS: [ ], VALIDATORS: [ ],
MESSAGES: { MESSAGES: {
'required': this.i18n('The channel is required when the playlist is public.') 'required': $localize`The channel is required when the playlist is public.`
} }
} }
} }

View File

@ -1,6 +1,5 @@
import { I18n } from '@ngx-translate/i18n-polyfill'
import { Validators, ValidatorFn, ValidationErrors, AbstractControl } from '@angular/forms'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'
import { BuildFormValidator } from './form-validator.service' import { BuildFormValidator } from './form-validator.service'
@Injectable() @Injectable()
@ -19,21 +18,21 @@ export class VideoValidatorsService {
readonly VIDEO_SCHEDULE_PUBLICATION_AT: BuildFormValidator readonly VIDEO_SCHEDULE_PUBLICATION_AT: BuildFormValidator
readonly VIDEO_ORIGINALLY_PUBLISHED_AT: BuildFormValidator readonly VIDEO_ORIGINALLY_PUBLISHED_AT: BuildFormValidator
constructor (private i18n: I18n) { constructor () {
this.VIDEO_NAME = { this.VIDEO_NAME = {
VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(120) ], VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(120) ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Video name is required.'), 'required': $localize`Video name is required.`,
'minlength': this.i18n('Video name must be at least 3 characters long.'), 'minlength': $localize`Video name must be at least 3 characters long.`,
'maxlength': this.i18n('Video name cannot be more than 120 characters long.') 'maxlength': $localize`Video name cannot be more than 120 characters long.`
} }
} }
this.VIDEO_PRIVACY = { this.VIDEO_PRIVACY = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Video privacy is required.') 'required': $localize`Video privacy is required.`
} }
} }
@ -60,46 +59,46 @@ export class VideoValidatorsService {
this.VIDEO_CHANNEL = { this.VIDEO_CHANNEL = {
VALIDATORS: [ Validators.required ], VALIDATORS: [ Validators.required ],
MESSAGES: { MESSAGES: {
'required': this.i18n('Video channel is required.') 'required': $localize`Video channel is required.`
} }
} }
this.VIDEO_DESCRIPTION = { this.VIDEO_DESCRIPTION = {
VALIDATORS: [ Validators.minLength(3), Validators.maxLength(10000) ], VALIDATORS: [ Validators.minLength(3), Validators.maxLength(10000) ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('Video description must be at least 3 characters long.'), 'minlength': $localize`Video description must be at least 3 characters long.`,
'maxlength': this.i18n('Video description cannot be more than 10000 characters long.') 'maxlength': $localize`Video description cannot be more than 10000 characters long.`
} }
} }
this.VIDEO_TAG = { this.VIDEO_TAG = {
VALIDATORS: [ Validators.minLength(2), Validators.maxLength(30) ], VALIDATORS: [ Validators.minLength(2), Validators.maxLength(30) ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('A tag should be more than 2 characters long.'), 'minlength': $localize`A tag should be more than 2 characters long.`,
'maxlength': this.i18n('A tag should be less than 30 characters long.') 'maxlength': $localize`A tag should be less than 30 characters long.`
} }
} }
this.VIDEO_TAGS_ARRAY = { this.VIDEO_TAGS_ARRAY = {
VALIDATORS: [ Validators.maxLength(5), this.arrayTagLengthValidator() ], VALIDATORS: [ Validators.maxLength(5), this.arrayTagLengthValidator() ],
MESSAGES: { MESSAGES: {
'maxlength': this.i18n('A maximum of 5 tags can be used on a video.'), 'maxlength': $localize`A maximum of 5 tags can be used on a video.`,
'arrayTagLength': this.i18n('A tag should be more than 2, and less than 30 characters long.') 'arrayTagLength': $localize`A tag should be more than 2, and less than 30 characters long.`
} }
} }
this.VIDEO_SUPPORT = { this.VIDEO_SUPPORT = {
VALIDATORS: [ Validators.minLength(3), Validators.maxLength(1000) ], VALIDATORS: [ Validators.minLength(3), Validators.maxLength(1000) ],
MESSAGES: { MESSAGES: {
'minlength': this.i18n('Video support must be at least 3 characters long.'), 'minlength': $localize`Video support must be at least 3 characters long.`,
'maxlength': this.i18n('Video support cannot be more than 1000 characters long.') 'maxlength': $localize`Video support cannot be more than 1000 characters long.`
} }
} }
this.VIDEO_SCHEDULE_PUBLICATION_AT = { this.VIDEO_SCHEDULE_PUBLICATION_AT = {
VALIDATORS: [ ], VALIDATORS: [ ],
MESSAGES: { MESSAGES: {
'required': this.i18n('A date is required to schedule video update.') 'required': $localize`A date is required to schedule video update.`
} }
} }

View File

@ -1,6 +1,5 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { Notifier } from '@app/core' import { Notifier } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({ @Component({
selector: 'my-input-readonly-copy', selector: 'my-input-readonly-copy',
@ -10,12 +9,9 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
export class InputReadonlyCopyComponent { export class InputReadonlyCopyComponent {
@Input() value = '' @Input() value = ''
constructor ( constructor (private notifier: Notifier) { }
private notifier: Notifier,
private i18n: I18n
) { }
activateCopiedMessage () { activateCopiedMessage () {
this.notifier.success(this.i18n('Copied')) this.notifier.success($localize`Copied`)
} }
} }

View File

@ -2,7 +2,6 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'
import { ServerService } from '@app/core' import { ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig } from '@shared/models' import { ServerConfig } from '@shared/models'
import { BytesPipe } from '../shared-main' import { BytesPipe } from '../shared-main'
@ -34,11 +33,10 @@ export class PreviewUploadComponent implements OnInit, ControlValueAccessor {
constructor ( constructor (
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private serverService: ServerService, private serverService: ServerService
private i18n: I18n
) { ) {
this.bytesPipe = new BytesPipe() this.bytesPipe = new BytesPipe()
this.maxSizeText = this.i18n('max size') this.maxSizeText = $localize`max size`
} }
get videoImageExtensions () { get videoImageExtensions () {

Some files were not shown because too many files have changed in this diff Show More