Added preliminary localization support to almost all strings in the program

pull/30/head
Isaac Grynsztein 6 years ago
parent c752b13732
commit 21797f3901

@ -25,6 +25,7 @@
"@angular/core": "^8.2.11", "@angular/core": "^8.2.11",
"@angular/forms": "^8.2.11", "@angular/forms": "^8.2.11",
"@angular/http": "^7.2.15", "@angular/http": "^7.2.15",
"@angular/localize": "^9.0.6",
"@angular/material": "^8.2.3", "@angular/material": "^8.2.3",
"@angular/platform-browser": "^8.2.11", "@angular/platform-browser": "^8.2.11",
"@angular/platform-browser-dynamic": "^8.2.11", "@angular/platform-browser-dynamic": "^8.2.11",

@ -14,12 +14,12 @@
<mat-menu #menuSettings="matMenu"> <mat-menu #menuSettings="matMenu">
<button (click)="themeMenuItemClicked($event)" *ngIf="allowThemeChange" mat-menu-item> <button (click)="themeMenuItemClicked($event)" *ngIf="allowThemeChange" mat-menu-item>
<mat-icon>{{(postsService.theme.key === 'default') ? 'brightness_5' : 'brightness_2'}}</mat-icon> <mat-icon>{{(postsService.theme.key === 'default') ? 'brightness_5' : 'brightness_2'}}</mat-icon>
<span>Dark</span> <span i18n="Dark mode toggle label">Dark</span>
<mat-slide-toggle class="theme-slide-toggle" [checked]="postsService.theme.key === 'dark'"></mat-slide-toggle> <mat-slide-toggle class="theme-slide-toggle" [checked]="postsService.theme.key === 'dark'"></mat-slide-toggle>
</button> </button>
<button (click)="openSettingsDialog()" mat-menu-item> <button (click)="openSettingsDialog()" mat-menu-item>
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
<span>Settings</span> <span i18n="Settings menu label">Settings</span>
</button> </button>
</mat-menu> </mat-menu>
</div> </div>
@ -30,8 +30,8 @@
<mat-sidenav-container style="height: 100%"> <mat-sidenav-container style="height: 100%">
<mat-sidenav #sidenav> <mat-sidenav #sidenav>
<mat-nav-list> <mat-nav-list>
<a mat-list-item (click)="sidenav.close()" routerLink='/home'>Home</a> <a mat-list-item (click)="sidenav.close()" routerLink='/home'><ng-container i18n="Navigation menu Home Page title">Home</ng-container></a>
<a mat-list-item (click)="sidenav.close()" routerLink='/subscriptions'>Subscriptions</a> <a mat-list-item (click)="sidenav.close()" routerLink='/subscriptions'><ng-container i18n="Navigation menu Subscriptions Page title">Subscriptions</ng-container></a>
</mat-nav-list> </mat-nav-list>
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content [style.background]="postsService.theme ? postsService.theme.background_color : null"> <mat-sidenav-content [style.background]="postsService.theme ? postsService.theme.background_color : null">

@ -1,13 +1,14 @@
<h4 mat-dialog-title>Create a playlist</h4> <h4 mat-dialog-title i18n="Create a playlist dialog title">Create a playlist</h4>
<form> <form>
<div> <div>
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [(ngModel)]="name" matInput placeholder="Name" type="text" required aria-required [ngModelOptions]="{standalone: true}"> <input [(ngModel)]="name" matInput placeholder="Name" i18n-placeholder="Playlist name placeholder" type="text" required aria-required [ngModelOptions]="{standalone: true}">
</mat-form-field> </mat-form-field>
</div> </div>
<div> <div>
<mat-form-field color="accent"> <mat-form-field color="accent">
<mat-label>{{(type === 'audio') ? 'Audio files' : 'Videos'}}</mat-label> <mat-label *ngIf="type === 'audio'"><ng-container i18n="Audio files title">Audio files</ng-container></mat-label>
<mat-label *ngIf="type === 'video'"><ng-container i18n="Videos title">Videos</ng-container></mat-label>
<mat-select [formControl]="filesSelect" multiple required aria-required> <mat-select [formControl]="filesSelect" multiple required aria-required>
<mat-option *ngFor="let file of filesToSelectFrom" [value]="file.id">{{file.id}}</mat-option> <mat-option *ngFor="let file of filesToSelectFrom" [value]="file.id">{{file.id}}</mat-option>
</mat-select> </mat-select>

@ -1,25 +1,25 @@
<h4 mat-dialog-title>Subscribe to playlist or channel</h4> <h4 mat-dialog-title i18n="Subscribe dialog title">Subscribe to playlist or channel</h4>
<mat-dialog-content> <mat-dialog-content>
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [(ngModel)]="url" matInput placeholder="URL" required aria-required="true"> <input [(ngModel)]="url" matInput placeholder="URL" i18n-placeholder="Subscription URL input placeholder" required aria-required="true">
<mat-hint>The playlist or channel URL</mat-hint> <mat-hint><ng-container i18n="Subscription URL input hint">The playlist or channel URL</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [(ngModel)]="name" matInput placeholder="Custom name"> <input [(ngModel)]="name" matInput placeholder="Custom name" i18n-placeholder="Subscription custom name placeholder">
<mat-hint>This is optional</mat-hint> <mat-hint><ng-container i18n="Custom name input hint">This is optional</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 mt-3"> <div class="col-12 mt-3">
<mat-checkbox [(ngModel)]="download_all">Download all uploads</mat-checkbox> <mat-checkbox [(ngModel)]="download_all"><ng-container i18n="Download all uploads subscription setting">Download all uploads</ng-container></mat-checkbox>
</div> </div>
<div class="col-12" *ngIf="!download_all"> <div class="col-12" *ngIf="!download_all">
Download videos uploaded in the last <ng-container i18n="Download time range prefix">Download videos uploaded in the last</ng-container>
<mat-form-field color="accent" style="width: 50px; text-align: center"> <mat-form-field color="accent" style="width: 50px; text-align: center">
<input type="number" matInput [(ngModel)]="timerange_amount"> <input type="number" matInput [(ngModel)]="timerange_amount">
</mat-form-field> </mat-form-field>
@ -34,7 +34,7 @@
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-button mat-dialog-close>Cancel</button> <button mat-button mat-dialog-close><ng-container i18n="Subscribe cancel button">Cancel</ng-container></button>
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. --> <!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
<button mat-button [disabled]="!url" type="submit" (click)="subscribeClicked()">Subscribe</button> <button mat-button [disabled]="!url" type="submit" (click)="subscribeClicked()">Subscribe</button>
<div class="mat-spinner" *ngIf="subscribing"> <div class="mat-spinner" *ngIf="subscribing">

@ -2,26 +2,26 @@
<mat-dialog-content> <mat-dialog-content>
<div class="info-item"> <div class="info-item">
<strong>Type: </strong> <strong><ng-container i18n="Subscription type property">Type:</ng-container>&nbsp;</strong>
<span class="info-item-value">{{(sub.isPlaylist ? 'Playlist' : 'Channel')}}</span> <span class="info-item-value">{{(sub.isPlaylist ? 'Playlist' : 'Channel')}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<strong>URL: </strong> <strong><ng-container i18n="Subscription URL property">URL:</ng-container>&nbsp;</strong>
<span class="info-item-value">{{sub.url}}</span> <span class="info-item-value">{{sub.url}}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<strong>ID: </strong> <strong><ng-container i18n="Subscription ID property">ID:</ng-container>&nbsp;</strong>
<span class="info-item-value">{{sub.id}}</span> <span class="info-item-value">{{sub.id}}</span>
</div> </div>
<div class="info-item" *ngIf="sub.archive"> <div class="info-item" *ngIf="sub.archive">
<strong>Archive: </strong> <strong><ng-container i18n="Subscription ID property">Archive:</ng-container>&nbsp;</strong>
<span class="info-item-value">{{sub.archive}}</span> <span class="info-item-value">{{sub.archive}}</span>
</div> </div>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-button mat-dialog-close>Close</button> <button mat-button mat-dialog-close><ng-container i18n="Close subscription info button">Close</ng-container></button>
<button mat-stroked-button (click)="downloadArchive()" color="accent">Export Archive</button> <button mat-stroked-button (click)="downloadArchive()" color="accent"><ng-container i18n="Export Archive button">Export Archive</ng-container></button>
<span class="spacer"></span> <span class="spacer"></span>
<button mat-button (click)="unsubscribe()" color="warn">Unsubscribe</button> <button mat-button (click)="unsubscribe()" color="warn"><ng-container i18n="Unsubscribe button">Unsubscribe</ng-container></button>
</mat-dialog-actions> </mat-dialog-actions>

@ -4,7 +4,7 @@
<h5 style="display: inline-block; margin-right: 5px; position: relative; top: 5px;">{{queueNumber}}.</h5> <h5 style="display: inline-block; margin-right: 5px; position: relative; top: 5px;">{{queueNumber}}.</h5>
</mat-grid-tile> </mat-grid-tile>
<mat-grid-tile [colspan]="6"> <mat-grid-tile [colspan]="6">
<div style="display: inline-block; text-align: center;">ID: {{url_id}}</div> <div style="display: inline-block; text-align: center;"><ng-container i18n="Download ID">ID:</ng-container>&nbsp;{{url_id}}</div>
</mat-grid-tile> </mat-grid-tile>
<mat-grid-tile [colspan]="13"> <mat-grid-tile [colspan]="13">
<mat-progress-bar style="width: 80%" [value]="download.percent_complete" [mode]="(download.percent_complete === 0) ? 'indeterminate' : 'determinate'"></mat-progress-bar> <mat-progress-bar style="width: 80%" [value]="download.percent_complete" [mode]="(download.percent_complete === 0) ? 'indeterminate' : 'determinate'"></mat-progress-bar>

@ -3,8 +3,8 @@
<div style="height: 52px;"> <div style="height: 52px;">
<b><a href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b> <b><a href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>
<br/> <br/>
<span class="max-two-lines">ID: {{name}}</span> <span class="max-two-lines"><ng-container i18n="File or playlist ID">ID:</ng-container>&nbsp;{{name}}</span>
<div *ngIf="isPlaylist">Count: {{count}}</div> <div *ngIf="isPlaylist"><ng-container i18n="Playlist video count">Count:</ng-container>&nbsp;{{count}}</div>
</div> </div>
<div *ngIf="!image_errored && thumbnailURL" class="img-div"> <div *ngIf="!image_errored && thumbnailURL" class="img-div">
<img class="image" (error) ="onImgError($event)" [id]="type" [lazyLoad]="thumbnailURL" [customObservable]="scrollAndLoad" (onLoad)="imageLoaded($event)" alt="Thumbnail"> <img class="image" (error) ="onImgError($event)" [id]="type" [lazyLoad]="thumbnailURL" [customObservable]="scrollAndLoad" (onLoad)="imageLoaded($event)" alt="Thumbnail">

@ -7,6 +7,7 @@
</div> </div>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<!-- TODO: Internationalize these buttons -->
<button mat-button mat-dialog-close>Cancel</button> <button mat-button mat-dialog-close>Cancel</button>
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. --> <!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
<button mat-button [disabled]="!inputText" type="submit" (click)="enterPressed()">{{submitText}}</button> <button mat-button [disabled]="!inputText" type="submit" (click)="enterPressed()">{{submitText}}</button>

@ -2,7 +2,7 @@
<div class="big demo-basic"> <div class="big demo-basic">
<mat-card id="card" style="margin-right: 20px; margin-left: 20px;"> <mat-card id="card" style="margin-right: 20px; margin-left: 20px;">
<mat-card-title> <mat-card-title>
Youtube Downloader <ng-container i18n="Youtube downloader home page label">Youtube Downloader</ng-container>
</mat-card-title> </mat-card-title>
<mat-card-content> <mat-card-content>
<div style="position: relative;"> <div style="position: relative;">
@ -12,13 +12,19 @@
<div [ngClass]="allowQualitySelect ? 'col-sm-9' : null" class="col-12"> <div [ngClass]="allowQualitySelect ? 'col-sm-9' : null" class="col-12">
<mat-form-field color="accent" class="example-full-width"> <mat-form-field color="accent" class="example-full-width">
<input style="padding-right: 25px;" matInput (ngModelChange)="inputChanged($event)" [(ngModel)]="url" [placeholder]="'URL' + (youtubeSearchEnabled ? ' or search' : '')" type="url" name="url" [formControl]="urlForm" required #urlinput> <input style="padding-right: 25px;" matInput (ngModelChange)="inputChanged($event)" [(ngModel)]="url" [placeholder]="'URL' + (youtubeSearchEnabled ? ' or search' : '')" type="url" name="url" [formControl]="urlForm" required #urlinput>
<mat-error *ngIf="urlError || urlForm.invalid">Please enter a valid URL!</mat-error> <mat-error *ngIf="urlError || urlForm.invalid">
<ng-container i18n="Enter valid URL error">Please enter a valid URL!</ng-container>
</mat-error>
<button class="input-clear-button" mat-icon-button (click)="clearInput()"><mat-icon>clear</mat-icon></button> <button class="input-clear-button" mat-icon-button (click)="clearInput()"><mat-icon>clear</mat-icon></button>
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="allowQualitySelect" class="col-7 col-sm-3"> <div *ngIf="allowQualitySelect" class="col-7 col-sm-3">
<mat-form-field color="accent" style="display: inline-block; width: inherit; min-width: 120px;"> <mat-form-field color="accent" style="display: inline-block; width: inherit; min-width: 120px;">
<mat-label>Quality</mat-label> <mat-label>
<ng-container i18n="Quality select label">
Quality
</ng-container>
</mat-label>
<mat-select [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality"> <mat-select [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality">
<ng-container *ngFor="let option of qualityOptions[(audioOnly) ? 'audio' : 'video']"> <ng-container *ngFor="let option of qualityOptions[(audioOnly) ? 'audio' : 'video']">
<mat-option *ngIf="option.value === '' || url && cachedAvailableFormats[url] && cachedAvailableFormats[url]['formats'] && cachedAvailableFormats[url]['formats'][(audioOnly) ? 'audio' : 'video'][option.value]" [value]="option.value"> <mat-option *ngIf="option.value === '' || url && cachedAvailableFormats[url] && cachedAvailableFormats[url]['formats'] && cachedAvailableFormats[url]['formats'][(audioOnly) ? 'audio' : 'video'][option.value]" [value]="option.value">
@ -42,22 +48,43 @@
<div style="font-size: 12px; margin-bottom: 10px;"> <div style="font-size: 12px; margin-bottom: 10px;">
{{result.uploaded}} {{result.uploaded}}
</div> </div>
<button mat-flat-button color="primary" style="float: left;" (click)="useURL(result.videoUrl)">Use URL</button> <button mat-flat-button color="primary" style="float: left;" (click)="useURL(result.videoUrl)">
<button mat-stroked-button color="primary" (click)="visitURL(result.videoUrl)" style="float: right">View</button> <ng-container i18n="YT search Use URL button for searched video">Use URL</ng-container>
</button>
<button mat-stroked-button color="primary" (click)="visitURL(result.videoUrl)" style="float: right">
<ng-container i18n="YT search View button for searched video">
View
</ng-container>
</button>
</mat-card> </mat-card>
</span> </span>
</div> </div>
</form> </form>
<br/> <br/>
<mat-checkbox [disabled]="current_download" (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px">Only Audio</mat-checkbox> <mat-checkbox [disabled]="current_download" (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px">
<mat-checkbox *ngIf="allowMultiDownloadMode" [disabled]="current_download" (change)="multiDownloadModeChanged($event)" [(ngModel)]="multiDownloadMode" style="float: right; margin-top: -12px">Multi-download mode</mat-checkbox> <ng-container i18n="Only Audio checkbox">
Only Audio
</ng-container>
</mat-checkbox>
<mat-checkbox *ngIf="allowMultiDownloadMode" [disabled]="current_download" (change)="multiDownloadModeChanged($event)" [(ngModel)]="multiDownloadMode" style="float: right; margin-top: -12px">
<ng-container i18n="Multi-download Mode checkbox">
Multi-download Mode
</ng-container>
</mat-checkbox>
</div> </div>
</mat-card-content> </mat-card-content>
<mat-card-actions> <mat-card-actions>
<button style="margin-left: 8px; margin-bottom: 8px" (click)="downloadClicked()" [disabled]="downloadingfile" type="submit" mat-stroked-button <button style="margin-left: 8px; margin-bottom: 8px" (click)="downloadClicked()" [disabled]="downloadingfile" type="submit" mat-stroked-button color="accent">
color="accent">Download</button> <ng-container i18n="Main download button">
<button (click)="cancelDownload()" style="float: right" *ngIf="!!current_download" mat-stroked-button color="warn">Cancel</button> Download
</ng-container>
</button>
<button (click)="cancelDownload()" style="float: right" *ngIf="!!current_download" mat-stroked-button color="warn">
<ng-container i18n="Cancel download button">
Cancel
</ng-container>
</button>
</mat-card-actions> </mat-card-actions>
</mat-card> </mat-card>
</div> </div>
@ -66,35 +93,60 @@
<mat-expansion-panel class="big"> <mat-expansion-panel class="big">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<ng-container i18n="Advanced download mode panel">
Advanced Advanced
</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<p *ngIf="this.simulatedOutput">Simulated command: <i>{{this.simulatedOutput}}</i></p> <p *ngIf="this.simulatedOutput">
<ng-container i18n="Simulated command label">
Simulated command:
</ng-container>
&nbsp;<i>{{this.simulatedOutput}}</i></p>
<div class="container" style="padding-bottom: 20px;"> <div class="container" style="padding-bottom: 20px;">
<div class="row"> <div class="row">
<div class="col-12 col-sm-6"> <div class="col-12 col-sm-6">
<mat-checkbox color="accent" [disabled]="current_download" (change)="customArgsEnabledChanged($event)" [(ngModel)]="customArgsEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">Use custom args</mat-checkbox> <mat-checkbox color="accent" [disabled]="current_download" (change)="customArgsEnabledChanged($event)" [(ngModel)]="customArgsEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
<ng-container i18n="Use custom args checkbox">
Use custom args
</ng-container>
</mat-checkbox>
<mat-form-field color="accent" style="margin-bottom: 42px;" class="advanced-input"> <mat-form-field color="accent" style="margin-bottom: 42px;" class="advanced-input">
<input [(ngModel)]="customArgs" [ngModelOptions]="{standalone: true}" [disabled]="!customArgsEnabled" matInput placeholder="Custom args"> <input [(ngModel)]="customArgs" [ngModelOptions]="{standalone: true}" [disabled]="!customArgsEnabled" matInput placeholder="Custom args" i18n-placeholder="Custom args placeholder">
<mat-hint>No need to include URL, just everything after.</mat-hint> <mat-hint>
<ng-container i18n="Custom Args input hint">
No need to include URL, just everything after.
</ng-container>
</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 col-sm-6"> <div class="col-12 col-sm-6">
<mat-checkbox color="accent" [disabled]="current_download" (change)="customOutputEnabledChanged($event)" [(ngModel)]="customOutputEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">Use custom output</mat-checkbox> <mat-checkbox color="accent" [disabled]="current_download" (change)="customOutputEnabledChanged($event)" [(ngModel)]="customOutputEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
<ng-container i18n="Use custom output checkbox">
Use custom output
</ng-container>
</mat-checkbox>
<mat-form-field style="margin-bottom: 42px;" color="accent" class="advanced-input"> <mat-form-field style="margin-bottom: 42px;" color="accent" class="advanced-input">
<input [(ngModel)]="customOutput" [ngModelOptions]="{standalone: true}" [disabled]="!customOutputEnabled" matInput placeholder="Custom output"> <input [(ngModel)]="customOutput" [ngModelOptions]="{standalone: true}" [disabled]="!customOutputEnabled" matInput placeholder="Custom output" i18n-placeholder="Custom output placeholder">
<mat-hint><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">Documentation</a>. Path is relative to the config download path. Don't include extension.</mat-hint> <mat-hint><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
<ng-container i18n="Youtube-dl output template documentation link">Documentation</ng-container></a>.
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-2"> <div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-2">
<mat-checkbox color="accent" [disabled]="current_download" (change)="youtubeAuthEnabledChanged($event)" [(ngModel)]="youtubeAuthEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">Use authentication</mat-checkbox> <mat-checkbox color="accent" [disabled]="current_download" (change)="youtubeAuthEnabledChanged($event)" [(ngModel)]="youtubeAuthEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
<ng-container i18n="Use authentication checkbox">
Use authentication
</ng-container>
</mat-checkbox>
<mat-form-field color="accent" class="advanced-input"> <mat-form-field color="accent" class="advanced-input">
<input [(ngModel)]="youtubeUsername" [ngModelOptions]="{standalone: true}" [disabled]="!youtubeAuthEnabled" matInput placeholder="Username"> <input [(ngModel)]="youtubeUsername" [ngModelOptions]="{standalone: true}" [disabled]="!youtubeAuthEnabled" matInput placeholder="Username" i18n-placeholder="YT Username placeholder">
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-2"> <div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-2">
<mat-form-field style="margin-top: 31px;" color="accent" class="advanced-input"> <mat-form-field style="margin-top: 31px;" color="accent" class="advanced-input">
<input [(ngModel)]="youtubePassword" type="password" [ngModelOptions]="{standalone: true}" [disabled]="!youtubeAuthEnabled" matInput placeholder="Password"> <input [(ngModel)]="youtubePassword" type="password" [ngModelOptions]="{standalone: true}" [disabled]="!youtubeAuthEnabled" matInput placeholder="Password" i18n-placeholder="YT Password placeholder">
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -138,10 +190,14 @@
<mat-expansion-panel (opened)="accordionOpened('audio')" (closed)="accordionClosed('audio')" (mouseleave)="accordionLeft('audio')" (mouseenter)="accordionEntered('audio')" class="big"> <mat-expansion-panel (opened)="accordionOpened('audio')" (closed)="accordionClosed('audio')" (mouseleave)="accordionLeft('audio')" (mouseenter)="accordionEntered('audio')" class="big">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<ng-container i18n="Audio files title">
Audio Audio
</ng-container>
</mat-panel-title> </mat-panel-title>
<mat-panel-description> <mat-panel-description>
<ng-container i18n="Audio files description">
Your audio files are here Your audio files are here
</ng-container>
</mat-panel-description> </mat-panel-description>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="mp3s.length > 0;else nomp3s"> <div *ngIf="mp3s.length > 0;else nomp3s">
@ -154,7 +210,7 @@
</mat-grid-list> </mat-grid-list>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<div style="width: 100%; text-align: center; margin-top: 10px;"> <div style="width: 100%; text-align: center; margin-top: 10px;">
<h6>Playlists</h6> <h6 i18n="Playlists title">Playlists</h6>
</div> </div>
<mat-grid-list *ngIf="playlists.audio.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px"> <mat-grid-list *ngIf="playlists.audio.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
<mat-grid-tile *ngFor="let playlist of playlists.audio; let i = index;"> <mat-grid-tile *ngFor="let playlist of playlists.audio; let i = index;">
@ -165,7 +221,9 @@
</mat-grid-list> </mat-grid-list>
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog('audio')" mat-fab><mat-icon>add</mat-icon></button></div> <div class="add-playlist-button"><button (click)="openCreatePlaylistDialog('audio')" mat-fab><mat-icon>add</mat-icon></button></div>
<div *ngIf="playlists.audio.length === 0"> <div *ngIf="playlists.audio.length === 0">
<ng-container i18n="No video playlists available text">
No playlists available. Create one from your downloading audio files by clicking the blue plus button. No playlists available. Create one from your downloading audio files by clicking the blue plus button.
</ng-container>
</div> </div>
</div> </div>
@ -173,10 +231,14 @@
<mat-expansion-panel (opened)="accordionOpened('video')" (closed)="accordionClosed('video')" (mouseleave)="accordionLeft('video')" (mouseenter)="accordionEntered('video')" class="big"> <mat-expansion-panel (opened)="accordionOpened('video')" (closed)="accordionClosed('video')" (mouseleave)="accordionLeft('video')" (mouseenter)="accordionEntered('video')" class="big">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<ng-container i18n="Video files title">
Video Video
</ng-container>
</mat-panel-title> </mat-panel-title>
<mat-panel-description> <mat-panel-description>
<ng-container i18n="Video files description">
Your video files are here Your video files are here
</ng-container>
</mat-panel-description> </mat-panel-description>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="mp4s.length > 0;else nomp4s"> <div *ngIf="mp4s.length > 0;else nomp4s">
@ -190,7 +252,7 @@
<mat-divider></mat-divider> <mat-divider></mat-divider>
<div style="width: 100%; text-align: center; margin-top: 10px;"> <div style="width: 100%; text-align: center; margin-top: 10px;">
<h6>Playlists</h6> <h6 i18n="Playlists title">Playlists</h6>
</div> </div>
<mat-grid-list *ngIf="playlists.video.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px"> <mat-grid-list *ngIf="playlists.video.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
<mat-grid-tile *ngFor="let playlist of playlists.video; let i = index;"> <mat-grid-tile *ngFor="let playlist of playlists.video; let i = index;">
@ -203,7 +265,9 @@
<!-- Add video playlist button --> <!-- Add video playlist button -->
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog('video')" mat-fab><mat-icon>add</mat-icon></button></div> <div class="add-playlist-button"><button (click)="openCreatePlaylistDialog('video')" mat-fab><mat-icon>add</mat-icon></button></div>
<div *ngIf="playlists.video.length === 0"> <div *ngIf="playlists.video.length === 0">
<ng-container i18n="No video playlists available text">
No playlists available. Create one from your downloading video files by clicking the blue plus button. No playlists available. Create one from your downloading video files by clicking the blue plus button.
</ng-container>
</div> </div>
</div> </div>
</mat-expansion-panel> </mat-expansion-panel>

@ -19,7 +19,7 @@
<div class="spinner-div"> <div class="spinner-div">
<mat-spinner *ngIf="playlist_updating" [diameter]="25"></mat-spinner> <mat-spinner *ngIf="playlist_updating" [diameter]="25"></mat-spinner>
</div> </div>
<button color="primary" [disabled]="playlist_updating" (click)="updatePlaylist()" mat-raised-button>Save changes <mat-icon>update</mat-icon></button> <button color="primary" [disabled]="playlist_updating" (click)="updatePlaylist()" mat-raised-button><ng-container i18n="Playlist save changes button">Save changes</ng-container>&nbsp;<mat-icon>update</mat-icon></button>
</div> </div>

@ -1,25 +1,25 @@
<h4 mat-dialog-title>Settings</h4> <h4 i18n="Settings title" mat-dialog-title>Settings</h4>
<!-- <ng-container i18n="Allow subscriptions setting"></ng-container> -->
<mat-dialog-content> <mat-dialog-content>
<!-- Host --> <!-- Host -->
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Host <ng-container i18n="Host settings title">Host</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [(ngModel)]="new_config['Host']['url']" matInput placeholder="URL" required> <input [(ngModel)]="new_config['Host']['url']" matInput placeholder="URL" i18n-placeholder="URL input placeholder" required>
<mat-hint>Base URL this app will be accessed from, without the port.</mat-hint> <mat-hint><ng-container i18n="URL setting input hint">URL this app will be accessed from, without the port.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 mt-4"> <div class="col-12 mt-4">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [(ngModel)]="new_config['Host']['port']" matInput placeholder="Port" required> <input [(ngModel)]="new_config['Host']['port']" matInput placeholder="Port" i18n-placeholder="Port input placeholder" required>
<mat-hint>The desired port. Default is 17442.</mat-hint> <mat-hint><ng-container i18n="Port setting input hint">The desired port. Default is 17442.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
@ -31,24 +31,24 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Encryption <ng-container i18n="Encryption settings title">Encryption</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Encryption']['use-encryption']">Use encryption</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Encryption']['use-encryption']"><ng-container i18n="Use encryption setting">Use encryption</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [disabled]="!new_config['Encryption']['use-encryption']" [(ngModel)]="new_config['Encryption']['cert-file-path']" matInput placeholder="Cert file path"> <input [disabled]="!new_config['Encryption']['use-encryption']" [(ngModel)]="new_config['Encryption']['cert-file-path']" matInput placeholder="Cert file path" i18n-placeholder="Cert file path input placeholder">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [disabled]="!new_config['Encryption']['use-encryption']" [(ngModel)]="new_config['Encryption']['key-file-path']" matInput placeholder="Key file path"> <input [disabled]="!new_config['Encryption']['use-encryption']" [(ngModel)]="new_config['Encryption']['key-file-path']" matInput placeholder="Key file path" i18n-placeholder="Key file path input placeholder">
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -59,29 +59,29 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Downloader <ng-container i18n="Downloader settings title">Downloader</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input matInput [(ngModel)]="new_config['Downloader']['path-audio']" placeholder="Audio folder path" required> <input matInput [(ngModel)]="new_config['Downloader']['path-audio']" placeholder="Audio folder path" i18n-placeholder="Audio folder path input placeholder" required>
<mat-hint>Path for audio only downloads. It is relative to YTDL-Material's root folder.</mat-hint> <mat-hint><ng-container i18n="Aduio path setting input hint">Path for audio only downloads. It is relative to YTDL-Material's root folder.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 mt-4"> <div class="col-12 mt-4">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input matInput [(ngModel)]="new_config['Downloader']['path-video']" placeholder="Video folder path" required> <input matInput [(ngModel)]="new_config['Downloader']['path-video']" placeholder="Video folder path" i18n-placeholder="Video folder path input placeholder" required>
<mat-hint>Path for video downloads. It is relative to YTDL-Material's root folder.</mat-hint> <mat-hint><ng-container i18n="Video path setting input hint">Path for video downloads. It is relative to YTDL-Material's root folder.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 mt-4"> <div class="col-12 mt-4">
<mat-form-field color="accent"> <mat-form-field color="accent">
<textarea matInput [(ngModel)]="new_config['Downloader']['custom_args']" placeholder="Custom args"></textarea> <textarea matInput [(ngModel)]="new_config['Downloader']['custom_args']" placeholder="Custom args" i18n-placeholder="Custom args input placeholder"></textarea>
<mat-hint>Global custom args for downloads on the home page.</mat-hint> <mat-hint><ng-container i18n="Custom args setting input hint">Global custom args for downloads on the home page.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -92,28 +92,28 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Extra <ng-container i18n="Extra settings title">Extra</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [(ngModel)]="new_config['Extra']['title_top']" matInput placeholder="Top title" required> <input [(ngModel)]="new_config['Extra']['title_top']" matInput placeholder="Top title" i18n-placeholder="Top title input placeholder" required>
<mat-hint></mat-hint> <mat-hint></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['file_manager_enabled']">File manager enabled</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['file_manager_enabled']"><ng-container i18n="File manager enabled setting">File manager enabled</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['allow_quality_select']">Allow quality select</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['allow_quality_select']"><ng-container i18n="Allow quality seelct setting">Allow quality select</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['download_only_mode']">Download only mode</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['download_only_mode']"><ng-container i18n="Download only mode setting">Download only mode</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['allow_multi_download_mode']">Allow multi-download mode</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Extra']['allow_multi_download_mode']"><ng-container i18n="Allow multi-downloade mode setting">Allow multi-download mode</ng-container></mat-checkbox>
</div> </div>
</div> </div>
</div> </div>
@ -123,18 +123,18 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
API <ng-container i18n="API settings title">API</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['API']['use_youtube_api']">Use YouTube API</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['API']['use_youtube_api']"><ng-container i18n="Use YouTube API setting">Use YouTube API</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [disabled]="!new_config['API']['use_youtube_api']" [(ngModel)]="new_config['API']['youtube_API_key']" matInput placeholder="Youtube API Key" required> <input [disabled]="!new_config['API']['use_youtube_api']" [(ngModel)]="new_config['API']['youtube_API_key']" matInput placeholder="Youtube API Key" i18n-placeholder="Youtube API Key setting placeholder" required>
<mat-hint><a target="_blank" href="https://developers.google.com/youtube/v3/getting-started">Generating a key</a> is easy!</mat-hint> <mat-hint><a target="_blank" href="https://developers.google.com/youtube/v3/getting-started"><ng-container i18n="Youtube API Key setting hint">Generating a key is easy!</ng-container></a></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -145,20 +145,20 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Themes <ng-container i18n="Themes settings title">Themes</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-select color="accent" style="width: 100px" [(ngModel)]="new_config['Themes']['default_theme']"> <mat-select color="accent" style="width: 100px" [(ngModel)]="new_config['Themes']['default_theme']">
<mat-option value="default">Default</mat-option> <mat-option value="default"><ng-container i18n="Default theme label">Default</ng-container></mat-option>
<mat-option value="dark">Dark</mat-option> <mat-option value="dark"><ng-container i18n="Dark theme label">Dark</ng-container></mat-option>
</mat-select> </mat-select>
</div> </div>
<div class="col-12 mt-4"> <div class="col-12 mt-4">
<mat-checkbox color="accent" [(ngModel)]="new_config['Themes']['allow_theme_change']">Allow theme change</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Themes']['allow_theme_change']"><ng-container i18n="Allow theme change setting">Allow theme change</ng-container></mat-checkbox>
</div> </div>
</div> </div>
</div> </div>
@ -168,30 +168,30 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Subscriptions <ng-container i18n="Subscriptions settings title">Subscriptions</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Subscriptions']['allow_subscriptions']">Allow subscriptions</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Subscriptions']['allow_subscriptions']"><ng-container i18n="Allow subscriptions setting">Allow subscriptions</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_base_path']" matInput placeholder="Subscriptions base path"> <input [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_base_path']" matInput placeholder="Subscriptions base path" i18n-placeholder="Subscriptions base path input setting placeholder">
<mat-hint>Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder.</mat-hint> <mat-hint><ng-container i18n="Subscriptions base path setting input hint">Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 mt-5"> <div class="col-12 mt-5">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_check_interval']" matInput placeholder="Check interval"> <input [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_check_interval']" matInput placeholder="Check interval" i18n-placeholder="Check interval input setting placeholder">
<mat-hint>Unit is seconds, only include numbers.</mat-hint> <mat-hint><ng-container i18n="Check interval setting input hint">Unit is seconds, only include numbers.</ng-container></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12 mt-4"> <div class="col-12 mt-4">
<mat-checkbox color="accent" [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_use_youtubedl_archive']">Use youtube-dl archive</mat-checkbox> <mat-checkbox color="accent" [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_use_youtubedl_archive']"><ng-container i18n="Use youtube-dl archive setting">Use youtube-dl archive</ng-container></mat-checkbox>
<p>With youtube-dl's <a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#how-do-i-download-only-new-videos-from-a-playlist">archive</a> feature, downloaded videos from your subscriptions get recorded in a text file in the subscriptions <i>archive</i> sub-directory.</p> <p><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#how-do-i-download-only-new-videos-from-a-playlist"><ng-container i18n="youtube-dl archive explanation prefix link">With youtube-dl's archive</ng-container></a>&nbsp;<ng-container i18n="youtube-dl archive explanation middle">feature, downloaded videos from your subscriptions get recorded in a text file in the subscriptions archive sub-directory.</ng-container></p>
<p>This enables the ability to permanently delete videos from your subscriptions without unsubscribing, and allows you to record which videos you downloaded in case of data loss.</p> <p><ng-container i18n="youtube-dl archive explanation suffix">This enables the ability to permanently delete videos from your subscriptions without unsubscribing, and allows you to record which videos you downloaded in case of data loss.</ng-container></p>
</div> </div>
</div> </div>
</div> </div>
@ -201,22 +201,22 @@
<mat-expansion-panel class="settings-expansion-panel"> <mat-expansion-panel class="settings-expansion-panel">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Advanced <ng-container i18n="Advanced settings title">Advanced</ng-container>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div *ngIf="new_config" class="container-fluid"> <div *ngIf="new_config" class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Advanced']['use_default_downloading_agent']">Use default downloading agent</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Advanced']['use_default_downloading_agent']"><ng-container i18n="Use default downloading agent setting">Use default downloading agent</ng-container></mat-checkbox>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field color="accent"> <mat-form-field color="accent">
<input [disabled]="new_config['Advanced']['use_default_downloading_agent']" [(ngModel)]="new_config['Advanced']['custom_downloading_agent']" matInput placeholder="Custom agent" required> <input [disabled]="new_config['Advanced']['use_default_downloading_agent']" [(ngModel)]="new_config['Advanced']['custom_downloading_agent']" matInput placeholder="Custom agent" i18n-placeholder="Custom agent setting placeholder" required>
<mat-hint></mat-hint> <mat-hint></mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-checkbox color="accent" [(ngModel)]="new_config['Advanced']['allow_advanced_download']">Allow advanced download</mat-checkbox> <mat-checkbox color="accent" [(ngModel)]="new_config['Advanced']['allow_advanced_download']"><ng-container i18n="Allow advanced downloading setting">Allow advanced download</ng-container></mat-checkbox>
</div> </div>
</div> </div>
</div> </div>
@ -225,7 +225,11 @@
<mat-dialog-actions> <mat-dialog-actions>
<div style="margin-bottom: 10px;"> <div style="margin-bottom: 10px;">
<button color="accent" (click)="saveSettings()" [disabled]="settingsSame()" mat-raised-button><mat-icon>done</mat-icon>&nbsp;&nbsp;Save</button> <button color="accent" (click)="saveSettings()" [disabled]="settingsSame()" mat-raised-button><mat-icon>done</mat-icon>&nbsp;&nbsp;
<button mat-flat-button [mat-dialog-close]="false"><mat-icon>cancel</mat-icon>&nbsp;&nbsp;Cancel</button> <ng-container i18n="Settings save button">Save</ng-container>
</button>
<button mat-flat-button [mat-dialog-close]="false"><mat-icon>cancel</mat-icon>&nbsp;&nbsp;
<ng-container i18n="Settings cancel button">Cancel</ng-container>
</button>
</div> </div>
</mat-dialog-actions> </mat-dialog-actions>

@ -1,11 +1,11 @@
<div style="position: relative; width: fit-content;"> <div style="position: relative; width: fit-content;">
<div class="duration-time"> <div class="duration-time">
Length: {{formattedDuration}} <ng-container i18n="Video duration label">Length:</ng-container>&nbsp;{{formattedDuration}}
</div> </div>
<button [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button> <button [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
<mat-menu #action_menu="matMenu"> <mat-menu #action_menu="matMenu">
<button (click)="deleteAndRedownload()" mat-menu-item><mat-icon>restore</mat-icon>Delete and redownload</button> <button (click)="deleteAndRedownload()" mat-menu-item><mat-icon>restore</mat-icon><ng-container i18n="Delete and redownload subscription video button">Delete and redownload</ng-container></button>
<button (click)="deleteForever()" mat-menu-item *ngIf="sub.archive && use_youtubedl_archive"><mat-icon>delete_forever</mat-icon>Delete forever</button> <button (click)="deleteForever()" mat-menu-item *ngIf="sub.archive && use_youtubedl_archive"><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete forever subscription video button">Delete forever</ng-container></button>
</mat-menu> </mat-menu>
<mat-card (click)="goToFile()" matRipple class="example-card mat-elevation-z6"> <mat-card (click)="goToFile()" matRipple class="example-card mat-elevation-z6">
<div style="padding:5px"> <div style="padding:5px">

@ -12,11 +12,11 @@
<div class="flex-grid"> <div class="flex-grid">
<div class="col"></div> <div class="col"></div>
<div class="col"> <div class="col">
<h4 style="text-align: center; margin-bottom: 20px;">Videos</h4> <h4 i18n="Subscription videos title" style="text-align: center; margin-bottom: 20px;">Videos</h4>
</div> </div>
<div class="col"> <div class="col">
<mat-form-field [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent"> <mat-form-field [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
<input (focus)="searchIsFocused = true" (blur)="searchIsFocused = false" class="search-input" type="text" placeholder="Search" [(ngModel)]="search_text" (ngModelChange)="onSearchInputChanged($event)" matInput> <input (focus)="searchIsFocused = true" (blur)="searchIsFocused = false" class="search-input" type="text" placeholder="Search" i18n-placeholder="Subscription videos search placeholder" [(ngModel)]="search_text" (ngModelChange)="onSearchInputChanged($event)" matInput>
<mat-icon matSuffix>search</mat-icon> <mat-icon matSuffix>search</mat-icon>
</mat-form-field> </mat-form-field>
</div> </div>

@ -1,20 +1,17 @@
<br/> <br/>
<h2 style="text-align: center; margin-bottom: 15px;">Your subscriptions</h2> <h2 i18n="Subscriptions title" style="text-align: center; margin-bottom: 15px;">Your subscriptions</h2>
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider> <mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
<br/> <br/>
<h4 style="text-align: center;">Channels</h4> <h4 i18n="Subscriptions channels title" style="text-align: center;">Channels</h4>
<mat-nav-list class="sub-nav-list"> <mat-nav-list class="sub-nav-list">
<mat-list-item *ngFor="let sub of channel_subscriptions"> <mat-list-item *ngFor="let sub of channel_subscriptions">
<a class="a-list-item" matLine (click)="goToSubscription(sub)" href="javascript:void(0)"> <a class="a-list-item" matLine (click)="goToSubscription(sub)" href="javascript:void(0)">
<strong *ngIf="sub.name">{{ sub.name }}</strong> <strong *ngIf="sub.name">{{ sub.name }}</strong>
<div *ngIf="!sub.name"> <div *ngIf="!sub.name">
Name not available. Channel retrieval in progress. <ng-container i18n="Subscription playlist not available text">Name not available. Channel retrieval in progress.</ng-container>
<ngx-content-loading *ngIf="false" [width]="200" [height]="20">
<svg:g ngx-rect width="200" height="20" y="0" x="0" rx="4" ry="4"></svg:g>
</ngx-content-loading>
</div> </div>
</a> </a>
<button mat-icon-button (click)="showSubInfo(sub)"> <button mat-icon-button (click)="showSubInfo(sub)">
@ -24,19 +21,16 @@
</mat-nav-list> </mat-nav-list>
<div style="width: 80%; margin: 0 auto; padding-left: 15px;" *ngIf="channel_subscriptions.length === 0 && subscriptions"> <div style="width: 80%; margin: 0 auto; padding-left: 15px;" *ngIf="channel_subscriptions.length === 0 && subscriptions">
<p>You have no channel subscriptions.</p> <p i18n="No channel subscriptions text">You have no channel subscriptions.</p>
</div> </div>
<h4 style="text-align: center; margin-top: 10px;">Playlists</h4> <h4 i18n="Subscriptions playlists title" style="text-align: center; margin-top: 10px;">Playlists</h4>
<mat-nav-list class="sub-nav-list"> <mat-nav-list class="sub-nav-list">
<mat-list-item *ngFor="let sub of playlist_subscriptions"> <mat-list-item *ngFor="let sub of playlist_subscriptions">
<a class="a-list-item" matLine (click)="goToSubscription(sub)" href="javascript:void(0)"> <a class="a-list-item" matLine (click)="goToSubscription(sub)" href="javascript:void(0)">
<strong>{{ sub.name }}</strong> <strong>{{ sub.name }}</strong>
<div class="content-loading-div" *ngIf="!sub.name"> <div class="content-loading-div" *ngIf="!sub.name">
Name not available. Playlist retrieval in progress. <ng-container i18n="Subscription playlist not available text">Name not available. Playlist retrieval in progress.</ng-container>
<ngx-content-loading *ngIf="false" [primaryColor]="postsService.theme.background_color" [secondaryColor]="postsService.theme.alternate_color" [width]="200" [height]="20">
<svg:g ngx-rect width="200" height="20" y="0" x="0" rx="4" ry="4"></svg:g>
</ngx-content-loading>
</div> </div>
</a> </a>
<button mat-icon-button (click)="showSubInfo(sub)"> <button mat-icon-button (click)="showSubInfo(sub)">
@ -46,7 +40,7 @@
</mat-nav-list> </mat-nav-list>
<div style="width: 80%; margin: 0 auto; padding-left: 15px;" *ngIf="playlist_subscriptions.length === 0 && subscriptions"> <div style="width: 80%; margin: 0 auto; padding-left: 15px;" *ngIf="playlist_subscriptions.length === 0 && subscriptions">
<p>You have no playlist subscriptions.</p> <p i18n="No playlist subscriptions text">You have no playlist subscriptions.</p>
</div> </div>
<div style="margin: 0 auto; width: 80%" *ngIf="subscriptions_loading"> <div style="margin: 0 auto; width: 80%" *ngIf="subscriptions_loading">

@ -1,3 +1,7 @@
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
/** /**
* This file includes polyfills needed by Angular and is loaded before the app. * This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file. * You can add your own extra polyfills to this file.

Loading…
Cancel
Save