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>
Advanced <ng-container i18n="Advanced download mode panel">
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>
Audio <ng-container i18n="Audio files title">
Audio
</ng-container>
</mat-panel-title> </mat-panel-title>
<mat-panel-description> <mat-panel-description>
Your audio files are here <ng-container i18n="Audio files description">
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">
No playlists available. Create one from your downloading audio files by clicking the blue plus button. <ng-container i18n="No video playlists available text">
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>
Video <ng-container i18n="Video files title">
Video
</ng-container>
</mat-panel-title> </mat-panel-title>
<mat-panel-description> <mat-panel-description>
Your video files are here <ng-container i18n="Video files description">
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">
No playlists available. Create one from your downloading video files by clicking the blue plus button. <ng-container i18n="No video playlists available text">
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