mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
v0.8.3.2 - A Small Hotfix (#3194)
Co-authored-by: Robbie Davis <robbie@therobbiedavis.com> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: Havokdan <havokdan@yahoo.com.br> Co-authored-by: daydreamrabbit <devrabbit90@gmail.com> Co-authored-by: 無情天 <kofzhanganguo@126.com>
This commit is contained in:
parent
77de5ccce3
commit
894b49bb76
@ -549,12 +549,15 @@ public class OpdsController : BaseApiController
|
||||
Id = readingListDto.Id.ToString(),
|
||||
Title = readingListDto.Title,
|
||||
Summary = readingListDto.Summary,
|
||||
Links = new List<FeedLink>()
|
||||
{
|
||||
CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, $"{prefix}{apiKey}/reading-list/{readingListDto.Id}"),
|
||||
CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"{baseUrl}api/image/readinglist-cover?readingListId={readingListDto.Id}&apiKey={apiKey}"),
|
||||
CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"{baseUrl}api/image/readinglist-cover?readingListId={readingListDto.Id}&apiKey={apiKey}")
|
||||
}
|
||||
Links =
|
||||
[
|
||||
CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation,
|
||||
$"{prefix}{apiKey}/reading-list/{readingListDto.Id}"),
|
||||
CreateLink(FeedLinkRelation.Image, FeedLinkType.Image,
|
||||
$"{baseUrl}api/image/readinglist-cover?readingListId={readingListDto.Id}&apiKey={apiKey}"),
|
||||
CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image,
|
||||
$"{baseUrl}api/image/readinglist-cover?readingListId={readingListDto.Id}&apiKey={apiKey}")
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
@ -573,7 +576,7 @@ public class OpdsController : BaseApiController
|
||||
|
||||
[HttpGet("{apiKey}/reading-list/{readingListId}")]
|
||||
[Produces("application/xml")]
|
||||
public async Task<IActionResult> GetReadingListItems(int readingListId, string apiKey)
|
||||
public async Task<IActionResult> GetReadingListItems(int readingListId, string apiKey, [FromQuery] int pageNumber = 0)
|
||||
{
|
||||
var userId = await GetUser(apiKey);
|
||||
if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds)
|
||||
@ -592,7 +595,7 @@ public class OpdsController : BaseApiController
|
||||
var feed = CreateFeed(readingList.Title + " " + await _localizationService.Translate(userId, "reading-list"), $"{apiKey}/reading-list/{readingListId}", apiKey, prefix);
|
||||
SetFeedId(feed, $"reading-list-{readingListId}");
|
||||
|
||||
var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId)).ToList();
|
||||
var items = await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId);
|
||||
foreach (var item in items)
|
||||
{
|
||||
var chapterDto = await _unitOfWork.ChapterRepository.GetChapterDtoAsync(item.ChapterId);
|
||||
|
@ -345,7 +345,7 @@ public class SettingsController : BaseApiController
|
||||
|
||||
if (updateBookmarks)
|
||||
{
|
||||
BackgroundJob.Enqueue(() => UpdateBookmarkDirectory(originalBookmarkDirectory, bookmarkDirectory));
|
||||
UpdateBookmarkDirectory(originalBookmarkDirectory, bookmarkDirectory);
|
||||
}
|
||||
|
||||
if (updateSettingsDto.EnableFolderWatching)
|
||||
@ -371,6 +371,7 @@ public class SettingsController : BaseApiController
|
||||
return Ok(updateSettingsDto);
|
||||
}
|
||||
|
||||
|
||||
private void UpdateBookmarkDirectory(string originalBookmarkDirectory, string bookmarkDirectory)
|
||||
{
|
||||
_directoryService.ExistOrCreate(bookmarkDirectory);
|
||||
|
@ -9,7 +9,7 @@ public class ConfirmEmailDto
|
||||
[Required]
|
||||
public string Token { get; set; } = default!;
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
[StringLength(256, MinimumLength = 6)]
|
||||
public string Password { get; set; } = default!;
|
||||
[Required]
|
||||
public string Username { get; set; } = default!;
|
||||
|
@ -9,6 +9,6 @@ public class ConfirmPasswordResetDto
|
||||
[Required]
|
||||
public string Token { get; set; } = default!;
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
[StringLength(256, MinimumLength = 6)]
|
||||
public string Password { get; set; } = default!;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public class ResetPasswordDto
|
||||
/// The new password
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
[StringLength(256, MinimumLength = 6)]
|
||||
public string Password { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// The old, existing password. If an admin is performing the change, this is not required. Otherwise, it is.
|
||||
|
@ -11,6 +11,6 @@ public class RegisterDto
|
||||
/// </summary>
|
||||
public string Email { get; init; } = default!;
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
[StringLength(256, MinimumLength = 6)]
|
||||
public string Password { get; set; } = default!;
|
||||
}
|
||||
|
@ -119,6 +119,7 @@ public class CacheService : ICacheService
|
||||
}
|
||||
|
||||
_logger.LogDebug("File Dimensions call for {Length} images took {Time}ms", dimensions.Count, sw.ElapsedMilliseconds);
|
||||
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Company>kavitareader.com</Company>
|
||||
<Product>Kavita</Product>
|
||||
<AssemblyVersion>0.8.3.1</AssemblyVersion>
|
||||
<AssemblyVersion>0.8.3.2</AssemblyVersion>
|
||||
<NeutralLanguage>en</NeutralLanguage>
|
||||
<TieredPGO>true</TieredPGO>
|
||||
</PropertyGroup>
|
||||
@ -20,4 +20,4 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.assert" Version="2.9.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -168,7 +168,7 @@ $image-width: 160px;
|
||||
font-size: 0.8rem;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
max-width: 110px;
|
||||
max-width: 98px;
|
||||
|
||||
a {
|
||||
overflow: hidden;
|
||||
|
@ -27,6 +27,10 @@
|
||||
padding: var(--bs-dropdown-item-padding-y) 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
// Robbie added this but it broke most of the uses
|
||||
//.dropdown-toggle {
|
||||
// padding-top: 0;
|
||||
|
@ -1,21 +1,25 @@
|
||||
<ng-container *transloco="let t; read: 'details-tab'">
|
||||
<div class="details pb-3">
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 ms-1">
|
||||
<h4 class="header">{{t('genres-title')}}</h4>
|
||||
<app-badge-expander [includeComma]="true" [items]="genres" [itemsTillExpander]="3">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx" let-last="last">
|
||||
<a href="javascript:void(0)" class="dark-exempt btn-icon" (click)="openGeneric(FilterField.Genres, item.id)">{{item.title}}</a>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
<div class="ms-3">
|
||||
<app-badge-expander [includeComma]="true" [items]="genres" [itemsTillExpander]="3">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx" let-last="last">
|
||||
<a href="javascript:void(0)" class="dark-exempt btn-icon" (click)="openGeneric(FilterField.Genres, item.id)">{{item.title}}</a>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 ms-1">
|
||||
<h4 class="header">{{t('tags-title')}}</h4>
|
||||
<app-badge-expander [includeComma]="true" [items]="tags" [itemsTillExpander]="3">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx" let-last="last">
|
||||
<a href="javascript:void(0)" class="dark-exempt btn-icon" (click)="openGeneric(FilterField.Tags, item.id)">{{item.title}}</a>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
<div class="ms-3">
|
||||
<app-badge-expander [includeComma]="true" [items]="tags" [itemsTillExpander]="3">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx" let-last="last">
|
||||
<a href="javascript:void(0)" class="dark-exempt btn-icon" (click)="openGeneric(FilterField.Tags, item.id)">{{item.title}}</a>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
@ -29,7 +33,7 @@
|
||||
</app-carousel-reel>
|
||||
</div>
|
||||
|
||||
@if (genres.length > 0 || tags.length > 0) {
|
||||
@if (genres.length > 0 || tags.length > 0 || webLinks.length > 0) {
|
||||
<div class="setting-section-break" aria-hidden="true"></div>
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,7 @@
|
||||
<p>{{t('description')}}</p>
|
||||
|
||||
<form [formGroup]="settingsForm">
|
||||
<p class="alert alert-warning">{{t('setting-description')}}</p>
|
||||
|
||||
@if (settingsForm.dirty) {
|
||||
<div class="alert alert-warning">{{t('test-warning')}}</div>
|
||||
}
|
||||
<p class="alert alert-warning">{{t('setting-description')}} {{t('test-warning')}}</p>
|
||||
|
||||
<div class="row g-0 mt-2">
|
||||
@if (settingsForm.get('hostName'); as formControl) {
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject, OnInit} from '@angular/core';
|
||||
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
|
||||
import {ToastrService} from 'ngx-toastr';
|
||||
import {debounceTime, distinctUntilChanged, filter, switchMap, take, tap} from 'rxjs';
|
||||
import {debounceTime, distinctUntilChanged, filter, map, switchMap, take, tap} from 'rxjs';
|
||||
import {SettingsService} from '../settings.service';
|
||||
import {ServerSettings} from '../_models/server-settings';
|
||||
import {
|
||||
NgbAlert,
|
||||
NgbTooltip
|
||||
} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {NgIf, NgTemplateOutlet, TitleCasePipe} from '@angular/common';
|
||||
import {AsyncPipe, NgIf, NgTemplateOutlet, TitleCasePipe} from '@angular/common';
|
||||
import {translate, TranslocoModule} from "@jsverse/transloco";
|
||||
import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
|
||||
import {ManageMediaIssuesComponent} from "../manage-media-issues/manage-media-issues.component";
|
||||
@ -25,7 +25,7 @@ import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [NgIf, ReactiveFormsModule, NgbTooltip, NgTemplateOutlet, TranslocoModule, SafeHtmlPipe,
|
||||
ManageMediaIssuesComponent, TitleCasePipe, NgbAlert, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, BytesPipe]
|
||||
ManageMediaIssuesComponent, TitleCasePipe, NgbAlert, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, BytesPipe, AsyncPipe]
|
||||
})
|
||||
export class ManageEmailSettingsComponent implements OnInit {
|
||||
|
||||
|
@ -21,7 +21,7 @@ import {allEncodeFormats} from '../_models/encode-format';
|
||||
import {ManageMediaIssuesComponent} from '../manage-media-issues/manage-media-issues.component';
|
||||
import {NgFor, NgIf, NgTemplateOutlet} from '@angular/common';
|
||||
import {translate, TranslocoDirective, TranslocoService} from "@jsverse/transloco";
|
||||
import {allCoverImageSizes} from '../_models/cover-image-size';
|
||||
import {allCoverImageSizes, CoverImageSize} from '../_models/cover-image-size';
|
||||
import {pageLayoutModes} from "../../_models/preferences/preferences";
|
||||
import {PageLayoutModePipe} from "../../_pipes/page-layout-mode.pipe";
|
||||
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
|
||||
@ -62,7 +62,7 @@ export class ManageMediaSettingsComponent implements OnInit {
|
||||
this.serverSettings = settings;
|
||||
this.settingsForm.addControl('encodeMediaAs', new FormControl(this.serverSettings.encodeMediaAs, [Validators.required]));
|
||||
this.settingsForm.addControl('bookmarksDirectory', new FormControl(this.serverSettings.bookmarksDirectory, [Validators.required]));
|
||||
this.settingsForm.addControl('coverImageSize', new FormControl(this.serverSettings.coverImageSize, [Validators.required]));
|
||||
this.settingsForm.addControl('coverImageSize', new FormControl(this.serverSettings.coverImageSize || CoverImageSize.Default, [Validators.required]));
|
||||
|
||||
// Automatically save settings as we edit them
|
||||
this.settingsForm.valueChanges.pipe(
|
||||
|
@ -107,7 +107,7 @@ export class ManageTasksSettingsComponent implements OnInit {
|
||||
},
|
||||
{
|
||||
name: 'sync-themes-task',
|
||||
description: 'sync-themes-desc',
|
||||
description: 'sync-themes-task-desc',
|
||||
api: this.serverService.syncThemes(),
|
||||
successMessage: 'sync-themes-success'
|
||||
},
|
||||
@ -143,72 +143,20 @@ export class ManageTasksSettingsComponent implements OnInit {
|
||||
this.logLevels = result.levels;
|
||||
this.serverSettings = result.settings;
|
||||
|
||||
// Create base controls for taskScan, taskBackup, taskCleanup
|
||||
this.settingsForm.addControl('taskScan', new FormControl(this.serverSettings.taskScan, [Validators.required]));
|
||||
this.settingsForm.addControl('taskBackup', new FormControl(this.serverSettings.taskBackup, [Validators.required]));
|
||||
this.settingsForm.addControl('taskCleanup', new FormControl(this.serverSettings.taskCleanup, [Validators.required]));
|
||||
|
||||
if (!this.taskFrequencies.includes(this.serverSettings.taskScan)) {
|
||||
this.settingsForm.get('taskScan')?.setValue(this.customOption);
|
||||
this.settingsForm.addControl('taskScanCustom', new FormControl(this.serverSettings.taskScan, [Validators.required]));
|
||||
} else {
|
||||
this.settingsForm.addControl('taskScanCustom', new FormControl('', [Validators.required]));
|
||||
}
|
||||
|
||||
if (!this.taskFrequencies.includes(this.serverSettings.taskBackup)) {
|
||||
this.settingsForm.get('taskBackup')?.setValue(this.customOption);
|
||||
this.settingsForm.addControl('taskBackupCustom', new FormControl(this.serverSettings.taskBackup, [Validators.required]));
|
||||
} else {
|
||||
this.settingsForm.addControl('taskBackupCustom', new FormControl('', [Validators.required]));
|
||||
}
|
||||
this.updateCustomFields('taskScan', 'taskScanCustom', this.taskFrequencies, this.serverSettings.taskScan);
|
||||
this.updateCustomFields('taskBackup', 'taskBackupCustom', this.taskFrequencies, this.serverSettings.taskBackup);
|
||||
this.updateCustomFields('taskCleanup', 'taskCleanupCustom', this.taskFrequenciesForCleanup, this.serverSettings.taskCleanup);
|
||||
|
||||
if (!this.taskFrequenciesForCleanup.includes(this.serverSettings.taskCleanup)) {
|
||||
this.settingsForm.get('taskCleanup')?.setValue(this.customOption);
|
||||
this.settingsForm.addControl('taskCleanupCustom', new FormControl(this.serverSettings.taskCleanup, [Validators.required]));
|
||||
} else {
|
||||
this.settingsForm.addControl('taskCleanupCustom', new FormControl('', [Validators.required]));
|
||||
}
|
||||
|
||||
this.settingsForm.get('taskScanCustom')?.valueChanges.pipe(
|
||||
debounceTime(100),
|
||||
switchMap(val => this.settingsService.isValidCronExpression(val)),
|
||||
tap(isValid => {
|
||||
if (isValid) {
|
||||
this.settingsForm.get('taskScanCustom')?.setErrors(null);
|
||||
} else {
|
||||
this.settingsForm.get('taskScanCustom')?.setErrors({invalidCron: true})
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe();
|
||||
|
||||
this.settingsForm.get('taskBackupCustom')?.valueChanges.pipe(
|
||||
debounceTime(100),
|
||||
switchMap(val => this.settingsService.isValidCronExpression(val)),
|
||||
tap(isValid => {
|
||||
if (isValid) {
|
||||
this.settingsForm.get('taskBackupCustom')?.setErrors(null);
|
||||
} else {
|
||||
this.settingsForm.get('taskBackupCustom')?.setErrors({invalidCron: true})
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe();
|
||||
|
||||
this.settingsForm.get('taskCleanupCustom')?.valueChanges.pipe(
|
||||
debounceTime(100),
|
||||
switchMap(val => this.settingsService.isValidCronExpression(val)),
|
||||
tap(isValid => {
|
||||
if (isValid) {
|
||||
this.settingsForm.get('taskCleanupCustom')?.setErrors(null);
|
||||
} else {
|
||||
this.settingsForm.get('taskCleanupCustom')?.setErrors({invalidCron: true})
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe();
|
||||
// Call the validation method for each custom control
|
||||
this.validateCronExpression('taskScanCustom');
|
||||
this.validateCronExpression('taskBackupCustom');
|
||||
this.validateCronExpression('taskCleanupCustom');
|
||||
|
||||
// Automatically save settings as we edit them
|
||||
this.settingsForm.valueChanges.pipe(
|
||||
@ -235,6 +183,35 @@ export class ManageTasksSettingsComponent implements OnInit {
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
// Custom logic to dynamically handle custom fields and validators
|
||||
updateCustomFields(controlName: string, customControlName: string, frequencyList: string[], currentSetting: string) {
|
||||
if (!frequencyList.includes(currentSetting)) {
|
||||
// If the setting is not in the predefined list, it's a custom value
|
||||
this.settingsForm.get(controlName)?.setValue(this.customOption);
|
||||
this.settingsForm.addControl(customControlName, new FormControl(currentSetting, [Validators.required]));
|
||||
} else {
|
||||
// Otherwise, reset the custom control (no need for Validators.required here)
|
||||
this.settingsForm.addControl(customControlName, new FormControl(''));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the custom fields for cron expressions
|
||||
validateCronExpression(controlName: string) {
|
||||
this.settingsForm.get(controlName)?.valueChanges.pipe(
|
||||
debounceTime(100),
|
||||
switchMap(val => this.settingsService.isValidCronExpression(val)),
|
||||
tap(isValid => {
|
||||
if (isValid) {
|
||||
this.settingsForm.get(controlName)?.setErrors(null);
|
||||
} else {
|
||||
this.settingsForm.get(controlName)?.setErrors({ invalidCron: true });
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
|
||||
resetForm() {
|
||||
this.settingsForm.get('taskScan')?.setValue(this.serverSettings.taskScan, {onlySelf: true, emitEvent: false});
|
||||
|
@ -112,6 +112,7 @@ export class AllSeriesComponent implements OnInit {
|
||||
private readonly cdRef: ChangeDetectorRef) {
|
||||
|
||||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||
console.log('url: ', this.route.snapshot);
|
||||
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
@ -22,7 +22,7 @@ import {ServerService} from "./_services/server.service";
|
||||
import {OutOfDateModalComponent} from "./announcements/_components/out-of-date-modal/out-of-date-modal.component";
|
||||
import {PreferenceNavComponent} from "./sidenav/preference-nav/preference-nav.component";
|
||||
import {Breakpoint, UtilityService} from "./shared/_services/utility.service";
|
||||
import {translate} from "@jsverse/transloco";
|
||||
import {TranslocoService} from "@jsverse/transloco";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -47,6 +47,7 @@ export class AppComponent implements OnInit {
|
||||
private readonly router = inject(Router);
|
||||
private readonly themeService = inject(ThemeService);
|
||||
private readonly document = inject(DOCUMENT);
|
||||
private readonly translocoService = inject(TranslocoService);
|
||||
|
||||
protected readonly Breakpoint = Breakpoint;
|
||||
|
||||
@ -126,6 +127,9 @@ export class AppComponent implements OnInit {
|
||||
// Bust locale cache
|
||||
localStorage.removeItem('@transloco/translations/timestamp');
|
||||
localStorage.removeItem('@transloco/translations');
|
||||
(this.translocoService as any).cache.delete(localStorage.getItem('kavita-locale') || 'en');
|
||||
(this.translocoService as any).cache.clear();
|
||||
localStorage.setItem('kavita--version', version);
|
||||
location.reload();
|
||||
}
|
||||
localStorage.setItem('kavita--version', version);
|
||||
|
@ -80,7 +80,7 @@
|
||||
@if (chapter.isSpecial) {
|
||||
{{chapter.title || chapter.range}}
|
||||
} @else {
|
||||
<app-entity-title [entity]="chapter" [prioritizeTitleName]="false"></app-entity-title>
|
||||
<app-entity-title [entity]="chapter" [prioritizeTitleName]="false" [libraryType]="libraryType"></app-entity-title>
|
||||
}
|
||||
</a>
|
||||
</span>
|
||||
|
@ -33,31 +33,50 @@
|
||||
@case (LibraryType.Manga) {
|
||||
@if (titleName !== '' && prioritizeTitleName) {
|
||||
@if (isChapter && includeChapter) {
|
||||
{{t('chapter') + ' ' + number + ' - ' }}
|
||||
@if (number === LooseLeafOrSpecial) {
|
||||
{{t('chapter') + ' - ' }}
|
||||
} @else {
|
||||
{{t('chapter') + ' ' + number + ' - ' }}
|
||||
}
|
||||
|
||||
}
|
||||
{{titleName}}
|
||||
} @else {
|
||||
@if (includeVolume && volumeTitle !== '') {
|
||||
{{number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
|
||||
@if (number !== LooseLeafOrSpecial && isChapter && includeVolume) {
|
||||
{{volumeTitle}}
|
||||
}
|
||||
}
|
||||
|
||||
{{number !== LooseLeafOrSpecial ? (isChapter ? (t('chapter') + ' ') + number : volumeTitle) : t('special')}}
|
||||
@if (number !== LooseLeafOrSpecial) {
|
||||
@if (isChapter) {
|
||||
{{t('chapter') + ' ' + number}}
|
||||
} @else {
|
||||
{{volumeTitle}}
|
||||
}
|
||||
} @else {
|
||||
{{t('special')}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@case (LibraryType.Book) {
|
||||
@if (titleName !== '' && prioritizeTitleName) {
|
||||
{{titleName}}
|
||||
} @else if (number === LooseLeafOrSpecial) {
|
||||
{{null | defaultValue}}
|
||||
} @else {
|
||||
{{volumeTitle}}
|
||||
{{t('book-num', {num: volumeTitle})}}
|
||||
}
|
||||
}
|
||||
|
||||
@case (LibraryType.LightNovel) {
|
||||
@if (titleName !== '' && prioritizeTitleName) {
|
||||
{{titleName}}
|
||||
} @else if (number === LooseLeafOrSpecial) {
|
||||
{{null | defaultValue}}
|
||||
} @else {
|
||||
{{volumeTitle}}
|
||||
{{t('book-num', {num: (isChapter ? number : volumeTitle)})}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { Chapter, LooseLeafOrDefaultNumber } from 'src/app/_models/chapter';
|
||||
import { LibraryType } from 'src/app/_models/library/library';
|
||||
import { Volume } from 'src/app/_models/volume';
|
||||
import {TranslocoModule} from "@jsverse/transloco";
|
||||
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
||||
|
||||
/**
|
||||
* This is primarily used for list item
|
||||
@ -12,7 +13,8 @@ import {TranslocoModule} from "@jsverse/transloco";
|
||||
selector: 'app-entity-title',
|
||||
standalone: true,
|
||||
imports: [
|
||||
TranslocoModule
|
||||
TranslocoModule,
|
||||
DefaultValuePipe
|
||||
],
|
||||
templateUrl: './entity-title.component.html',
|
||||
styleUrls: ['./entity-title.component.scss'],
|
||||
@ -20,7 +22,6 @@ import {TranslocoModule} from "@jsverse/transloco";
|
||||
})
|
||||
export class EntityTitleComponent implements OnInit {
|
||||
|
||||
protected readonly LooseLeafOrSpecialNumber = LooseLeafOrDefaultNumber;
|
||||
protected readonly LooseLeafOrSpecial = LooseLeafOrDefaultNumber + "";
|
||||
protected readonly LibraryType = LibraryType;
|
||||
|
||||
@ -59,6 +60,7 @@ export class EntityTitleComponent implements OnInit {
|
||||
this.volumeTitle = c.volumeTitle || '';
|
||||
this.titleName = c.titleName || '';
|
||||
this.number = c.range;
|
||||
|
||||
} else {
|
||||
const v = this.utilityService.asVolume(this.entity);
|
||||
this.volumeTitle = v.name || '';
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import {BulkOperationsComponent} from "../cards/bulk-operations/bulk-operations.component";
|
||||
import {TagBadgeComponent} from "../shared/tag-badge/tag-badge.component";
|
||||
import {AsyncPipe, DecimalPipe, DOCUMENT, NgStyle, NgClass, DatePipe} from "@angular/common";
|
||||
import {AsyncPipe, DecimalPipe, DOCUMENT, NgStyle, NgClass, DatePipe, Location} from "@angular/common";
|
||||
import {CardActionablesComponent} from "../_single-module/card-actionables/card-actionables.component";
|
||||
import {CarouselReelComponent} from "../carousel/_components/carousel-reel/carousel-reel.component";
|
||||
import {ExternalSeriesCardComponent} from "../cards/external-series-card/external-series-card.component";
|
||||
@ -171,6 +171,7 @@ export class ChapterDetailComponent implements OnInit {
|
||||
private readonly messageHub = inject(MessageHubService);
|
||||
private readonly actionFactoryService = inject(ActionFactoryService);
|
||||
private readonly actionService = inject(ActionService);
|
||||
private readonly location = inject(Location);
|
||||
|
||||
protected readonly AgeRating = AgeRating;
|
||||
protected readonly TabID = TabID;
|
||||
@ -331,8 +332,9 @@ export class ChapterDetailComponent implements OnInit {
|
||||
}
|
||||
|
||||
updateUrl(activeTab: TabID) {
|
||||
const newUrl = `${this.router.url.split('#')[0]}#${activeTab}`;
|
||||
window.history.replaceState({}, '', newUrl);
|
||||
const tokens = this.location.path().split('#');
|
||||
const newUrl = `${tokens[0]}#${activeTab}`;
|
||||
this.location.replaceState(newUrl)
|
||||
}
|
||||
|
||||
openPerson(field: FilterField, value: number) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {
|
||||
AsyncPipe,
|
||||
DecimalPipe,
|
||||
DOCUMENT, JsonPipe,
|
||||
DOCUMENT, JsonPipe, Location,
|
||||
NgClass,
|
||||
NgOptimizedImage,
|
||||
NgStyle,
|
||||
@ -211,6 +211,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
||||
protected readonly themeService = inject(ThemeService);
|
||||
private readonly filterUtilityService = inject(FilterUtilitiesService);
|
||||
private readonly scrobbleService = inject(ScrobblingService);
|
||||
private readonly location = inject(Location);
|
||||
|
||||
protected readonly LibraryType = LibraryType;
|
||||
protected readonly TabID = TabID;
|
||||
@ -523,6 +524,8 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
||||
|
||||
|
||||
this.route.fragment.pipe(tap(frag => {
|
||||
if (frag !== null && this.activeTabId !== (frag as TabID)) {
|
||||
this.activeTabId = frag as TabID;
|
||||
@ -561,9 +564,9 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
|
||||
updateUrl(activeTab: TabID) {
|
||||
var tokens = this.router.url.split('#');
|
||||
const tokens = this.location.path().split('#');
|
||||
const newUrl = `${tokens[0]}#${activeTab}`;
|
||||
window.history.replaceState({}, '', newUrl);
|
||||
this.location.replaceState(newUrl)
|
||||
}
|
||||
|
||||
handleSeriesActionCallback(action: ActionItem<Series>, series: Series) {
|
||||
|
@ -69,7 +69,9 @@ export class SettingItemComponent {
|
||||
if (!this.toggleOnViewClick) return false;
|
||||
|
||||
const mouseEvent = event as MouseEvent;
|
||||
return !elementRef.nativeElement.contains(mouseEvent.target)
|
||||
const selection = window.getSelection();
|
||||
const hasSelection = selection !== null && selection.toString().trim() === '';
|
||||
return !elementRef.nativeElement.contains(mouseEvent.target) && hasSelection;
|
||||
}),
|
||||
tap(() => {
|
||||
this.isEditMode = false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, Params, Router} from '@angular/router';
|
||||
import {SortField, SortOptions} from 'src/app/_models/metadata/series-filter';
|
||||
import {MetadataService} from "../../_services/metadata.service";
|
||||
@ -12,6 +12,7 @@ import {TextResonse} from "../../_types/text-response";
|
||||
import {environment} from "../../../environments/environment";
|
||||
import {map, tap} from "rxjs/operators";
|
||||
import {of, switchMap} from "rxjs";
|
||||
import {Location} from "@angular/common";
|
||||
|
||||
|
||||
@Injectable({
|
||||
@ -19,9 +20,12 @@ import {of, switchMap} from "rxjs";
|
||||
})
|
||||
export class FilterUtilitiesService {
|
||||
|
||||
private apiUrl = environment.apiUrl;
|
||||
private readonly location = inject(Location);
|
||||
private readonly router = inject(Router);
|
||||
private readonly metadataService = inject(MetadataService);
|
||||
private readonly http = inject(HttpClient);
|
||||
|
||||
constructor(private metadataService: MetadataService, private router: Router, private http: HttpClient) {}
|
||||
private apiUrl = environment.apiUrl;
|
||||
|
||||
encodeFilter(filter: SeriesFilterV2 | undefined) {
|
||||
return this.http.post<string>(this.apiUrl + 'filter/encode', filter, TextResonse);
|
||||
|
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
@if (!item.isProvided) {
|
||||
<div class="ps-1">
|
||||
<a [href]="'/all-series?' + this.item.smartFilterEncoded" target="_blank">{{t('load-filter')}}</a>
|
||||
<a [href]="baseUrl + 'all-series?' + this.item.smartFilterEncoded" target="_blank">{{t('load-filter')}}</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
EventEmitter, inject,
|
||||
Input,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import {CommonModule, NgClass} from '@angular/common';
|
||||
import {APP_BASE_HREF, CommonModule, NgClass} from '@angular/common';
|
||||
import {ImageComponent} from "../../../shared/image/image.component";
|
||||
import {MangaFormatIconPipe} from "../../../_pipes/manga-format-icon.pipe";
|
||||
import {MangaFormatPipe} from "../../../_pipes/manga-format.pipe";
|
||||
@ -13,11 +13,12 @@ import {NgbProgressbar} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {TranslocoDirective} from "@jsverse/transloco";
|
||||
import {DashboardStream} from "../../../_models/dashboard/dashboard-stream";
|
||||
import {StreamNamePipe} from "../../../_pipes/stream-name.pipe";
|
||||
import {RouterLink} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard-stream-list-item',
|
||||
standalone: true,
|
||||
imports: [ImageComponent, MangaFormatIconPipe, MangaFormatPipe, NgbProgressbar, TranslocoDirective, StreamNamePipe, NgClass],
|
||||
imports: [ImageComponent, MangaFormatIconPipe, MangaFormatPipe, NgbProgressbar, TranslocoDirective, StreamNamePipe, NgClass, RouterLink],
|
||||
templateUrl: './dashboard-stream-list-item.component.html',
|
||||
styleUrls: ['./dashboard-stream-list-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
@ -26,4 +27,5 @@ export class DashboardStreamListItemComponent {
|
||||
@Input({required: true}) item!: DashboardStream;
|
||||
@Input({required: true}) position: number = 0;
|
||||
@Output() hide: EventEmitter<DashboardStream> = new EventEmitter<DashboardStream>();
|
||||
protected readonly baseUrl = inject(APP_BASE_HREF);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
<i class="fa-solid fa-triangle-exclamation red me-2" [ngbTooltip]="t('errored')"></i>
|
||||
<span class="visually-hidden">{{t('errored')}}</span>
|
||||
}
|
||||
<a [href]="'/all-series?' + f.filter" target="_blank">{{f.name}}</a>
|
||||
<a [href]="baseUrl + 'all-series?' + f.filter" target="_blank">{{f.name}}</a>
|
||||
</span>
|
||||
<button class="btn btn-danger float-end" (click)="deleteFilter(f)">
|
||||
<i class="fa-solid fa-trash" aria-hidden="true"></i>
|
||||
|
@ -6,11 +6,13 @@ import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
|
||||
import {FilterPipe} from "../../../_pipes/filter.pipe";
|
||||
import {ActionService} from "../../../_services/action.service";
|
||||
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {RouterLink} from "@angular/router";
|
||||
import {APP_BASE_HREF} from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-smart-filters',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, TranslocoDirective, FilterPipe, NgbTooltip],
|
||||
imports: [ReactiveFormsModule, TranslocoDirective, FilterPipe, NgbTooltip, RouterLink],
|
||||
templateUrl: './manage-smart-filters.component.html',
|
||||
styleUrls: ['./manage-smart-filters.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
@ -20,6 +22,7 @@ export class ManageSmartFiltersComponent {
|
||||
private readonly filterService = inject(FilterService);
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
private readonly actionService = inject(ActionService);
|
||||
protected readonly baseUrl = inject(APP_BASE_HREF);
|
||||
|
||||
filters: Array<SmartFilter> = [];
|
||||
listForm: FormGroup = new FormGroup({
|
||||
|
@ -2,12 +2,12 @@
|
||||
<div class="row pt-2 g-0 list-item">
|
||||
<div class="g-0">
|
||||
<h5 class="mb-1 pb-0" id="item.id--{{position}}">
|
||||
<span *ngIf="item.isProvided; else nonProvidedTitle">
|
||||
@if (item.isProvided) {
|
||||
{{item.name | streamName }}
|
||||
</span>
|
||||
<ng-template #nonProvidedTitle>
|
||||
} @else {
|
||||
{{item.name}}
|
||||
</ng-template>
|
||||
}
|
||||
|
||||
<span class="float-end">
|
||||
<button class="btn btn-icon p-0" (click)="hide.emit(item)">
|
||||
<i class="me-1" [ngClass]="{'fas fa-eye': item.visible, 'fa-solid fa-eye-slash': !item.visible}" aria-hidden="true"></i>
|
||||
@ -29,10 +29,10 @@
|
||||
<div class="ps-1" *ngIf="!item.isProvided">
|
||||
<ng-container [ngSwitch]="item.streamType">
|
||||
<ng-container *ngSwitchCase="SideNavStreamType.Library">
|
||||
<a [href]="'/library/' + this.item.libraryId" target="_blank">{{item.library?.name}}</a>
|
||||
<a [href]="baseUrl + 'library/' + this.item.libraryId" target="_blank">{{item.library?.name}}</a>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="SideNavStreamType.SmartFilter">
|
||||
<a [href]="'/all-series?' + this.item.smartFilterEncoded" target="_blank">{{t('load-filter')}}</a>
|
||||
<a [href]="baseUrl + 'all-series?' + this.item.smartFilterEncoded">{{t('load-filter')}}</a>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="SideNavStreamType.ExternalSource">
|
||||
<a [href]="item.externalSource!.host! + 'login?apiKey=' + item.externalSource!.apiKey" target="_blank" rel="noopener noreferrer">{{item.externalSource!.host!}}</a>
|
||||
|
@ -1,14 +1,15 @@
|
||||
import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output} from '@angular/core';
|
||||
import {APP_BASE_HREF, CommonModule} from '@angular/common';
|
||||
import {SideNavStream} from "../../../_models/sidenav/sidenav-stream";
|
||||
import {StreamNamePipe} from "../../../_pipes/stream-name.pipe";
|
||||
import {TranslocoDirective} from "@jsverse/transloco";
|
||||
import {SideNavStreamType} from "../../../_models/sidenav/sidenav-stream-type.enum";
|
||||
import {RouterLink} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidenav-stream-list-item',
|
||||
standalone: true,
|
||||
imports: [CommonModule, StreamNamePipe, TranslocoDirective],
|
||||
imports: [CommonModule, StreamNamePipe, TranslocoDirective, RouterLink],
|
||||
templateUrl: './sidenav-stream-list-item.component.html',
|
||||
styleUrls: ['./sidenav-stream-list-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
@ -18,4 +19,10 @@ export class SidenavStreamListItemComponent {
|
||||
@Input({required: true}) position: number = 0;
|
||||
@Output() hide: EventEmitter<SideNavStream> = new EventEmitter<SideNavStream>();
|
||||
protected readonly SideNavStreamType = SideNavStreamType;
|
||||
protected readonly baseUrl = inject(APP_BASE_HREF);
|
||||
|
||||
constructor() {
|
||||
console.log('baseUrl', this.baseUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import {AsyncPipe, DecimalPipe, DOCUMENT, NgStyle, NgClass, DatePipe} from "@angular/common";
|
||||
import {AsyncPipe, DecimalPipe, DOCUMENT, NgStyle, NgClass, DatePipe, Location} from "@angular/common";
|
||||
import {ActivatedRoute, Router, RouterLink} from "@angular/router";
|
||||
import {ImageService} from "../_services/image.service";
|
||||
import {SeriesService} from "../_services/series.service";
|
||||
@ -198,6 +198,7 @@ export class VolumeDetailComponent implements OnInit {
|
||||
protected readonly utilityService = inject(UtilityService);
|
||||
private readonly readingListService = inject(ReadingListService);
|
||||
private readonly messageHub = inject(MessageHubService);
|
||||
private readonly location = inject(Location);
|
||||
|
||||
|
||||
protected readonly AgeRating = AgeRating;
|
||||
@ -555,8 +556,9 @@ export class VolumeDetailComponent implements OnInit {
|
||||
}
|
||||
|
||||
updateUrl(activeTab: TabID) {
|
||||
const newUrl = `${this.router.url.split('#')[0]}#${activeTab}`;
|
||||
window.history.replaceState({}, '', newUrl);
|
||||
const tokens = this.location.path().split('#');
|
||||
const newUrl = `${tokens[0]}#${activeTab}`;
|
||||
this.location.replaceState(newUrl)
|
||||
}
|
||||
|
||||
openPerson(field: FilterField, value: number) {
|
||||
|
@ -625,7 +625,7 @@
|
||||
"continue-incognito": "Unsichtbar fortsetzen",
|
||||
"incognito": "Unsichtbar",
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"edit-series-alt": "Bearbeite die Serieninformationen",
|
||||
"edit-series-alt": "Informationen bearbeiten",
|
||||
"user-reviews-local": "Lokale Bewertungen",
|
||||
"user-reviews-plus": "Externe Bewertungen",
|
||||
"cover-artists-title": "{{metadata-fields.cover-artists-title}}",
|
||||
@ -832,8 +832,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Spezial",
|
||||
"issue-num": "Ausgabe #",
|
||||
"chapter": "Kapitel"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"external-series-card": {
|
||||
"open-external": "Extern öffnen"
|
||||
@ -867,7 +868,7 @@
|
||||
"email-settings-title": "E-Mail-Einstellungen",
|
||||
"outlook-label": "Outlook",
|
||||
"setting-description": "Sie müssen sowohl den Hostnamen als auch die SMTP-Einstellungen ausfüllen, um die E-Mail-basierten Funktionen von Kavita nutzen zu können.",
|
||||
"test-warning": "Sie müssen speichern, bevor Sie die Schaltfläche Test verwenden.",
|
||||
"test-warning": "Sie müssen über gültige Einstellungen verfügen, bevor Sie auf „Testen“ klicken.",
|
||||
"size-limit-tooltip": "Wie viele Bytes kann der E-Mail-Server für Anhänge verarbeiten",
|
||||
"customized-templates-label": "Angepasste Templates"
|
||||
},
|
||||
@ -1135,7 +1136,7 @@
|
||||
},
|
||||
"filter-field-pipe": {
|
||||
"want-to-read": "Möchte ich lesen",
|
||||
"cover-artist": "Cover Künstler",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"read-time": "Lesezeit",
|
||||
"location": "Standort",
|
||||
"file-path": "Datei-Pfad",
|
||||
@ -1251,7 +1252,7 @@
|
||||
"character": "Charakter",
|
||||
"editor": "Editor",
|
||||
"publisher": "Herausgeber",
|
||||
"cover-artist": "Cover Künstler",
|
||||
"cover-artist": "{{artist}}",
|
||||
"translator": "Übersetzer",
|
||||
"colorist": "Kolorist",
|
||||
"imprint": "Impressum",
|
||||
|
@ -527,7 +527,7 @@
|
||||
"artist": "Artist",
|
||||
"character": "Character",
|
||||
"colorist": "Colorist",
|
||||
"cover-artist": "Cover Artist",
|
||||
"cover-artist": "{{artist}}",
|
||||
"editor": "Editor",
|
||||
"inker": "Inker",
|
||||
"letterer": "Letterer",
|
||||
@ -788,7 +788,7 @@
|
||||
"incognito": "Incognito",
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "Edit Series Information",
|
||||
"edit-series-alt": "Edit Information",
|
||||
"reviews-tab": "{{tabs.reviews-tab}}",
|
||||
"storyline-tab": "{{tabs.storyline-tab}}",
|
||||
"books-tab": "{{tabs.books-tab}}",
|
||||
@ -1109,8 +1109,9 @@
|
||||
|
||||
"entity-title": {
|
||||
"special": "Special",
|
||||
"issue-num": "Issue #",
|
||||
"chapter": "Chapter"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
|
||||
"external-series-card": {
|
||||
@ -1132,7 +1133,7 @@
|
||||
"manage-email-settings": {
|
||||
"description": "In order to use some functions of Kavita like Send To Device an email provider must be setup. Other features like Forgot Password require admin intervention without Email setup.",
|
||||
"setting-description": "You must fill out both Host Name and SMTP settings to use email-based functionality within Kavita.",
|
||||
"test-warning": "You must save before using Test button.",
|
||||
"test-warning": "You must have valid settings before hitting Test.",
|
||||
"send-to-warning": "If you want Send to Device to work you must setup your email settings",
|
||||
"email-url-label": "Email Service URL",
|
||||
"email-url-tooltip": "Use fully qualified URL of the email service. Do not include ending slash.",
|
||||
@ -2188,7 +2189,7 @@
|
||||
"characters": "{{metadata-fields.characters-title}}",
|
||||
"collection-tags": "Collection Tags",
|
||||
"colorist": "Colorist",
|
||||
"cover-artist": "Cover Artist",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"editor": "Editor",
|
||||
"formats": "Formats",
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
|
@ -614,7 +614,7 @@
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"incognito": "Incógnito",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "Editar informacion de la serie",
|
||||
"edit-series-alt": "Editar información",
|
||||
"volumes-tab": "{{tabs.volumes-tab}}",
|
||||
"specials-tab": "{{tabs.specials-tab}}",
|
||||
"related-tab": "{{tabs.related-tab}}",
|
||||
@ -895,7 +895,7 @@
|
||||
"artist": "Artista",
|
||||
"writer": "Escritor",
|
||||
"character": "Personaje",
|
||||
"cover-artist": "Artista de portada",
|
||||
"cover-artist": "{{artist}}",
|
||||
"editor": "Editor",
|
||||
"other": "Otro",
|
||||
"publisher": "Editorial",
|
||||
@ -1469,8 +1469,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Especial",
|
||||
"chapter": "Capítulo",
|
||||
"issue-num": "Número #"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"external-series-card": {
|
||||
"open-external": "Abrir externamente"
|
||||
@ -1506,7 +1507,7 @@
|
||||
"outlook-label": "Outlook",
|
||||
"gmail-label": "Gmail",
|
||||
"setting-description": "Para poder utilizar las funciones de correo electrónico de Kavita, debes rellenar los campos nombre del host y SMTP.",
|
||||
"test-warning": "Debes guardar antes de utilizar el botón Probar."
|
||||
"test-warning": "Debe tener configuraciones válidas antes de presionar Probar."
|
||||
},
|
||||
"cover-image-size": {
|
||||
"xlarge": "Extragrande (1265x1795)",
|
||||
@ -1658,7 +1659,7 @@
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
"release-year": "{{sort-field-pipe.release-year}}",
|
||||
"writers": "{{metadata-fields.writers-title}}",
|
||||
"cover-artist": "Artista de la portada",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"read-progress": "Progreso de la lectura",
|
||||
"editor": "Editor",
|
||||
"read-time": "Tiempo de lectura",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"username": "{{common.username}}",
|
||||
"password": "{{common.password}}",
|
||||
"password-validation": "{{validation.password-validation}}",
|
||||
"forgot-password": "Mot de passe oublié ?",
|
||||
"forgot-password": "Mot de passe oublié?",
|
||||
"submit": "Se connecter"
|
||||
},
|
||||
"dashboard": {
|
||||
@ -416,7 +416,7 @@
|
||||
"other": "Autre",
|
||||
"penciller": "Crayonneur",
|
||||
"letterer": "Lettreur",
|
||||
"cover-artist": "Artiste de la couverture",
|
||||
"cover-artist": "{{artist}}",
|
||||
"character": "Personnage",
|
||||
"artist": "Artiste",
|
||||
"inker": "Encreur",
|
||||
@ -668,7 +668,7 @@
|
||||
"collection-tags": "Étiquettes de la collection",
|
||||
"characters": "{{metadata-fields.characters-title}}",
|
||||
"languages": "Langues",
|
||||
"cover-artist": "Artiste de couverture",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"writers": "{{metadata-fields.writers-title}}",
|
||||
"release-year": "{{sort-field-pipe.release-year}}",
|
||||
"read-progress": "Progrès de lecture",
|
||||
@ -987,7 +987,7 @@
|
||||
"read-incognito": "Lire en mode privé",
|
||||
"specials-tab": "{{tabs.specials-tab}}",
|
||||
"recommendations-tab": "{{tabs.recommendations-tab}}",
|
||||
"edit-series-alt": "Modifier les informations sur la série",
|
||||
"edit-series-alt": "Modifier les informations",
|
||||
"layout-mode-option-list": "Liste",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"no-pages": "{{toasts.no-pages}}",
|
||||
@ -1317,7 +1317,7 @@
|
||||
"gmail-label": "Gmail",
|
||||
"outlook-label": "Outlook",
|
||||
"setting-description": "Vous devez remplir les paramètres Nom d'hôte et SMTP pour utiliser les fonctionnalités de messagerie électronique dans Kavita.",
|
||||
"test-warning": "Vous devez enregistrer avant d'utiliser le bouton Test."
|
||||
"test-warning": "Vous devez avoir des paramètres valides avant de cliquer sur Test."
|
||||
},
|
||||
"bulk-add-to-collection": {
|
||||
"collection-label": "Collection",
|
||||
@ -1332,8 +1332,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Spécial",
|
||||
"chapter": "Chapitre",
|
||||
"issue-num": "Numéro #"
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"manage-library": {
|
||||
"add-library": "Ajouter une bibliothèque",
|
||||
|
@ -345,7 +345,7 @@
|
||||
"read-options-alt": "Léigh roghanna",
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "Cuir Eolas faoin tSraith in Eagar",
|
||||
"edit-series-alt": "Cuir Eolas in Eagar",
|
||||
"storyline-tab": "{{tabs.storyline-tab}}",
|
||||
"books-tab": "{{tabs.books-tab}}",
|
||||
"volumes-tab": "{{tabs.volumes-tab}}",
|
||||
@ -524,7 +524,7 @@
|
||||
"gmail-label": "GmailName",
|
||||
"description": "Chun úsáid a bhaint as roinnt feidhmeanna de chuid Kavita cosúil le Send To Device ní mór soláthraí ríomhphoist a shocrú. Teastaíonn idirghabháil riaracháin ó ghnéithe eile cosúil le Forgot Password gan socrú Ríomhphost.",
|
||||
"setting-description": "Ní mór duit socruithe Ainm Óstach agus SMTP araon a líonadh chun feidhmiúlacht ríomhphost-bhunaithe a úsáid laistigh de Kavita.",
|
||||
"test-warning": "Ní mór duit sábháil sula n-úsáideann tú cnaipe Tástála.",
|
||||
"test-warning": "Ní mór socruithe bailí a bheith agat sula mbuaileann tú Tástáil.",
|
||||
"send-to-warning": "Más mian leat Seol chuig gléas a bheith ag obair ní mór duit do shocruithe ríomhphoist a shocrú",
|
||||
"email-url-label": "URL na Seirbhíse Ríomhphoist",
|
||||
"email-url-tooltip": "Úsáid URL láncháilithe na seirbhíse ríomhphoist. Ná cuir deireadh le slais.",
|
||||
@ -1134,7 +1134,7 @@
|
||||
"characters": "{{metadata-fields.characters-title}}",
|
||||
"collection-tags": "Clibeanna Bailiúcháin",
|
||||
"colorist": "Dathóir",
|
||||
"cover-artist": "Ealaíontóir Clúdaigh",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"editor": "Eagarthóir",
|
||||
"formats": "Formáidí",
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
@ -1849,8 +1849,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Speisialta",
|
||||
"issue-num": "Eisiúint #",
|
||||
"chapter": "Caibidil 1009"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"external-series-card": {
|
||||
"open-external": "Oscail Seachtrach"
|
||||
|
@ -693,11 +693,11 @@
|
||||
"annual": "연간"
|
||||
},
|
||||
"publication-status-pipe": {
|
||||
"ended": "종료",
|
||||
"ongoing": "진행중",
|
||||
"hiatus": "중단",
|
||||
"ended": "누락",
|
||||
"ongoing": "연재중",
|
||||
"hiatus": "휴재",
|
||||
"completed": "완결",
|
||||
"cancelled": "취소"
|
||||
"cancelled": "연재중단"
|
||||
},
|
||||
"person-role-pipe": {
|
||||
"character": "캐릭터",
|
||||
@ -705,7 +705,7 @@
|
||||
"writer": "작가",
|
||||
"other": "그 외",
|
||||
"artist": "작가",
|
||||
"cover-artist": "표지 작가",
|
||||
"cover-artist": "{{artist}}",
|
||||
"editor": "편집자",
|
||||
"inker": "잉커",
|
||||
"letterer": "레터러",
|
||||
@ -825,7 +825,7 @@
|
||||
"series-detail": {
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "시리즈 정보 편집",
|
||||
"edit-series-alt": "정보 편집",
|
||||
"no-pages": "{{toasts.no-pages}}",
|
||||
"no-chapters": "이 볼륨에는 챕터가 없습니다. 읽을 수 없습니다.",
|
||||
"cover-change": "브라우저에서 이미지를 새로 고치는 데 최대 1분이 걸릴 수 있습니다. 그때까지는 일부 페이지에 이전 이미지가 표시될 수 있습니다.",
|
||||
@ -982,8 +982,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "스페셜",
|
||||
"issue-num": "이슈 #",
|
||||
"chapter": "챕터"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"manage-email-settings": {
|
||||
"reset": "{{common.reset}}",
|
||||
@ -1016,7 +1017,7 @@
|
||||
"username-tooltip": "호스트에 대해 인증하는 데 사용되는 사용자 이름",
|
||||
"host-tooltip": "이메일 서버의 발신/SMTP 주소",
|
||||
"setting-description": "Kavita 내에서 이메일 기반 기능을 사용하려면 호스트 이름과 SMTP 설정을 모두 입력해야 합니다.",
|
||||
"test-warning": "테스트 버튼을 사용하기 전에 반드시 저장해야 합니다."
|
||||
"test-warning": "테스트를 누르기 전에 설정이 유효해야 합니다."
|
||||
},
|
||||
"manage-scrobble-errors": {
|
||||
"edit-item-alt": "편집 {{seriesName}}",
|
||||
@ -1885,7 +1886,7 @@
|
||||
"filter-field-pipe": {
|
||||
"collection-tags": "컬렉션 태그",
|
||||
"colorist": "컬러리스트",
|
||||
"cover-artist": "커버 아티스트",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"editor": "편집자",
|
||||
"summary": "요약",
|
||||
"tags": "{{metadata-fields.tags-title}}",
|
||||
|
@ -622,7 +622,7 @@
|
||||
},
|
||||
"series-detail": {
|
||||
"continue": "Kontynuuj",
|
||||
"edit-series-alt": "Edytuj informacje o serii",
|
||||
"edit-series-alt": "Edytuj informacje",
|
||||
"storyline-tab": "{{tabs.storyline-tab}}",
|
||||
"recommendations-tab": "{{tabs.recommendations-tab}}",
|
||||
"send-to": "Plik wysłany e-mailem do {{deviceName}}",
|
||||
@ -1199,7 +1199,7 @@
|
||||
"size-limit-tooltip": "Ile bajtów może obsłużyć serwer poczty e-mail dla załączników",
|
||||
"gmail-label": "Gmail",
|
||||
"outlook-label": "Outlook",
|
||||
"test-warning": "Musisz zapisać przed użyciem przycisku Test.",
|
||||
"test-warning": "Przed naciśnięciem przycisku Test wprowadź prawidłowe ustawienia.",
|
||||
"setting-description": "Aby korzystać z funkcji poczty e-mail w Kavita, należy wypełnić zarówno ustawienia nazwy hosta, jak i SMTP."
|
||||
},
|
||||
"manage-media-settings": {
|
||||
@ -1403,8 +1403,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Special",
|
||||
"chapter": "Rozdział",
|
||||
"issue-num": "Wydanie #"
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"card-detail-layout": {
|
||||
"jumpkey-count": "{{count}} Serii",
|
||||
|
@ -462,7 +462,7 @@
|
||||
"artist": "Artista",
|
||||
"character": "Personagem",
|
||||
"colorist": "Colorista",
|
||||
"cover-artist": "Artista de Capa",
|
||||
"cover-artist": "{{artist}}",
|
||||
"editor": "Editor",
|
||||
"inker": "Arte-Finalista",
|
||||
"letterer": "Letrista",
|
||||
@ -682,7 +682,7 @@
|
||||
"incognito": "Incógnito",
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "Editar Informação da Série",
|
||||
"edit-series-alt": "Editar informações",
|
||||
"storyline-tab": "{{tabs.storyline-tab}}",
|
||||
"books-tab": "{{tabs.books-tab}}",
|
||||
"volumes-tab": "{{tabs.volumes-tab}}",
|
||||
@ -917,8 +917,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Especial",
|
||||
"issue-num": "Número #",
|
||||
"chapter": "Capítulo"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"external-series-card": {
|
||||
"open-external": "Abrir Externo"
|
||||
@ -953,7 +954,7 @@
|
||||
"username-tooltip": "O nome de utilizador usado para autenticar no host",
|
||||
"outlook-label": "Outlook",
|
||||
"gmail-label": "Gmail",
|
||||
"test-warning": "Tem de gravar antes de usar o botão Teste.",
|
||||
"test-warning": "Deve ter definições válidas antes de clicar em Teste.",
|
||||
"setting-description": "Tem de preencher o nome do Host e as definições de SMTP para poder usar as funcionalidades do Kavita baseadas em email."
|
||||
},
|
||||
"manage-library": {
|
||||
@ -1890,7 +1891,7 @@
|
||||
},
|
||||
"filter-field-pipe": {
|
||||
"age-rating": "{{metadata-fields.age-rating-title}}",
|
||||
"cover-artist": "Artista de Capa",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"formats": "Formatos",
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
"libraries": "Bibliotecas",
|
||||
|
@ -462,7 +462,7 @@
|
||||
"artist": "Artista",
|
||||
"character": "Personagem",
|
||||
"colorist": "Colorista",
|
||||
"cover-artist": "Artista da Capa",
|
||||
"cover-artist": "{{artist}}",
|
||||
"editor": "Editor",
|
||||
"inker": "Arte-finalista",
|
||||
"letterer": "Letrista",
|
||||
@ -682,7 +682,7 @@
|
||||
"incognito": "Incógnito",
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "Editar Informações da Série",
|
||||
"edit-series-alt": "Editar informações",
|
||||
"storyline-tab": "{{tabs.storyline-tab}}",
|
||||
"books-tab": "{{tabs.books-tab}}",
|
||||
"volumes-tab": "{{tabs.volumes-tab}}",
|
||||
@ -917,8 +917,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "Especial",
|
||||
"issue-num": "Número #",
|
||||
"chapter": "Capítulo"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"external-series-card": {
|
||||
"open-external": "Abrir Externamente"
|
||||
@ -953,7 +954,7 @@
|
||||
"username-tooltip": "O nome de usuário usado para autenticação no host",
|
||||
"gmail-label": "Gmail",
|
||||
"outlook-label": "Outlook",
|
||||
"test-warning": "Você deve salvar antes de usar o botão Teste.",
|
||||
"test-warning": "Você deve ter configurações válidas antes de clicar em Testar.",
|
||||
"setting-description": "Você deve preencher as configurações de nome do host e SMTP para usar a funcionalidade baseada em e-mail no Kavita."
|
||||
},
|
||||
"manage-library": {
|
||||
@ -1171,8 +1172,8 @@
|
||||
"series-tab": "{{tabs.series-tab}}",
|
||||
"name-label": "Nome",
|
||||
"name-validation": "Nome deve ser único",
|
||||
"promote-label": "Promoção",
|
||||
"promote-tooltip": "Promoção significa que a tag pode ser vista em todo o servidor, não apenas para usuários administrativos. Todas as séries que possuem essa tag ainda terão restrições de acesso do usuário.",
|
||||
"promote-label": "Divulgar",
|
||||
"promote-tooltip": "Divulgação significa que a etiqueta pode ser vista em todo o servidor, não apenas para usuários administrativos. Todas as séries que possuem essa etiqueta ainda terão restrições de acesso do usuário.",
|
||||
"summary-label": "Sumário",
|
||||
"deselect-all": "{{common.deselect-all}}",
|
||||
"select-all": "{{common.select-all}}",
|
||||
@ -1319,8 +1320,8 @@
|
||||
"month-label": "Mês",
|
||||
"ending-title": "Terminando",
|
||||
"starting-title": "Começando",
|
||||
"promote-label": "Promover",
|
||||
"promote-tooltip": "Promoção significa que a coleção pode ser vista em todo o servidor, não apenas para você. Todas as séries desta coleção ainda terão restrições de acesso do usuário."
|
||||
"promote-label": "Divulgar",
|
||||
"promote-tooltip": "Divulgação significa que a coleção pode ser vista em todo o servidor, não apenas para você. Todas as séries desta coleção ainda terão restrições de acesso do usuário."
|
||||
},
|
||||
"import-cbl-modal": {
|
||||
"close": "{{common.close}}",
|
||||
@ -1705,8 +1706,8 @@
|
||||
"confirm-download-size-ios": "O iOS tem problemas para baixar arquivos maiores que 200 MB; esse download pode não ser concluído.",
|
||||
"confirm-delete-collections": "Tem certeza de que deseja excluir várias coleções?",
|
||||
"collection-not-owned": "Você não possui esta coleção",
|
||||
"collections-promoted": "Coleções promovidas",
|
||||
"collections-unpromoted": "Coleções não promovidas",
|
||||
"collections-promoted": "Coleções divulgadas",
|
||||
"collections-unpromoted": "Coleções não divulgadas",
|
||||
"collections-deleted": "Coleções excluídas",
|
||||
"pdf-book-mode-screen-size": "Tela muito pequena para o modo Livro",
|
||||
"stack-imported": "Pilha Importada",
|
||||
@ -1714,11 +1715,11 @@
|
||||
"mal-token-required": "O token MAL é obrigatório, definido nas Configurações do Usuário",
|
||||
"reading-lists-deleted": "Listas de leitura excluídas",
|
||||
"confirm-delete-reading-lists": "Tem certeza de que deseja excluir as listas de leitura? Isto não pode ser desfeito.",
|
||||
"reading-lists-unpromoted": "Listas de leitura não promovidas",
|
||||
"reading-lists-promoted": "Listas de leitura promovidas",
|
||||
"reading-list-promoted": "Lista de Leitura promovida",
|
||||
"reading-lists-unpromoted": "Listas de leitura não divulgadas",
|
||||
"reading-lists-promoted": "Listas de leitura divulgadas",
|
||||
"reading-list-promoted": "Lista de Leitura divulgadas",
|
||||
"confirm-reset-server-settings": "Isso redefinirá suas configurações para os valores da primeira instalação. Tem certeza de que deseja continuar?",
|
||||
"reading-list-unpromoted": "Lista de Leitura não promovida",
|
||||
"reading-list-unpromoted": "Lista de Leitura não divulgadas",
|
||||
"generate-colorscape-queued": "Gerar colorscape na fila para {{name}}",
|
||||
"chapter-deleted": "Capítulo excluído",
|
||||
"confirm-delete-chapter": "Tem certeza de que deseja excluir este capítulo? Não modificará arquivos no disco.",
|
||||
@ -1754,8 +1755,8 @@
|
||||
"mark-invisible": "Marcar como Invisível",
|
||||
"mark-visible": "Marcar como Visível",
|
||||
"import-mal-stack": "Importar Pilha do Mal",
|
||||
"unpromote": "Não Promover",
|
||||
"promote": "Promover",
|
||||
"unpromote": "Não Divulgar",
|
||||
"promote": "Divulgar",
|
||||
"generate-colorscape": "Gerar ColorScape",
|
||||
"new-collection": "Nova Coleção",
|
||||
"multiple-selections": "Múltiplas Seleções",
|
||||
@ -1765,7 +1766,7 @@
|
||||
"mark-as-read-tooltip": "Marcar o progresso como totalmente lido",
|
||||
"scan-library-tooltip": "Escanear a biblioteca em busca de alterações. Use o escaneamento forçado para forçar a verificação de todas as pastas",
|
||||
"analyze-files-tooltip": "Analisar Arquivos quanto ao tipo e tamanho da extensão",
|
||||
"unpromote-tooltip": "Restringir a visibilidade apenas à sua conta",
|
||||
"unpromote-tooltip": "Restringi a visibilidade apenas à sua conta",
|
||||
"generate-colorscape-tooltip": "Gerar colorscapes e quaisquer capas ausentes",
|
||||
"edit-tooltip": "Editar configurações ou detalhes",
|
||||
"remove-from-on-deck-tooltip": "Remover séries da exibição no Na Estante",
|
||||
@ -1854,7 +1855,7 @@
|
||||
"loading": "Carregando…",
|
||||
"username": "Nome do usuário",
|
||||
"password": "Senha",
|
||||
"promoted": "Promovido",
|
||||
"promoted": "Divulgado",
|
||||
"select-all": "Selecionar Tudo",
|
||||
"deselect-all": "Deselecionar Todos",
|
||||
"series-count": "{{num}} Séries",
|
||||
@ -1893,7 +1894,7 @@
|
||||
"characters": "{{metadata-fields.characters-title}}",
|
||||
"collection-tags": "Coleção de Tags",
|
||||
"colorist": "Colorista",
|
||||
"cover-artist": "Artista da Capa",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"editor": "Editor",
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
"inker": "Arte-finalista",
|
||||
|
@ -158,7 +158,7 @@
|
||||
"pdf-theme-label": "主题",
|
||||
"pdf-scroll-mode-label": "滚动模式",
|
||||
"pdf-scroll-mode-tooltip": "您如何滚动页面。垂直/水平和点击翻页(无滚动)",
|
||||
"pdf-spread-mode-label": "页面传播模式",
|
||||
"pdf-spread-mode-label": "页面阅读模式",
|
||||
"background-color-tooltip": "图像阅读器的背景颜色",
|
||||
"auto-close-menu-tooltip": "菜单应该自动关闭",
|
||||
"show-screen-hints-tooltip": "显示覆盖以帮助了解分页区域和方向",
|
||||
@ -206,7 +206,7 @@
|
||||
},
|
||||
"restriction-selector": {
|
||||
"title": "年龄分级限制",
|
||||
"description": "选中后,全部系列和至少存在一个条目的阅读清单,其年龄限制大于下面选择的,将从结果中移除。",
|
||||
"description": "选中后,全部系列和至少存在一个条目的阅读列表,其年龄限制大于下面选择的,将从结果中移除。",
|
||||
"not-applicable-for-admins": "不适用于管理员。",
|
||||
"age-rating-label": "{{metadata-fields.age-rating-title}}",
|
||||
"no-restriction": "无限制",
|
||||
@ -405,7 +405,7 @@
|
||||
"cbl-conflict-reason-pipe": {
|
||||
"all-series-missing": "您的账户无法访问列表中的所有系列,或者Kavita在列表中没有任何内容。",
|
||||
"chapter-missing": "{{series}}: Kavita缺少第{{chapter}}章节。此项目将被跳过。",
|
||||
"empty-file": "cbl文件为空,没有任何操作可以进行。",
|
||||
"empty-file": "cbl 文件为空,没有任何操作可以进行。",
|
||||
"name-conflict": "您的账户已经存在一个与cbl文件匹配的阅读列表({{readingListName}})。",
|
||||
"series-collision": "系列{{seriesLink}}与另一个资料库中同名的系列发生冲突。",
|
||||
"series-missing": "系列{{series}}在Kavita中缺失,或者您的账户没有权限。所有带有此系列的项目将在导入时被跳过。",
|
||||
@ -462,7 +462,7 @@
|
||||
"artist": "设计师",
|
||||
"character": "角色",
|
||||
"colorist": "上色师",
|
||||
"cover-artist": "封面设计",
|
||||
"cover-artist": "{{artist}}",
|
||||
"editor": "编辑",
|
||||
"inker": "上墨师",
|
||||
"letterer": "嵌字师",
|
||||
@ -682,7 +682,7 @@
|
||||
"incognito": "隐身模式",
|
||||
"remove-from-want-to-read": "{{actionable.remove-from-want-to-read}}",
|
||||
"add-to-want-to-read": "{{actionable.add-to-want-to-read}}",
|
||||
"edit-series-alt": "编辑系列信息",
|
||||
"edit-series-alt": "編輯訊息",
|
||||
"storyline-tab": "{{tabs.storyline-tab}}",
|
||||
"books-tab": "{{tabs.books-tab}}",
|
||||
"volumes-tab": "{{tabs.volumes-tab}}",
|
||||
@ -752,7 +752,7 @@
|
||||
"home": "主页",
|
||||
"want-to-read": "想读",
|
||||
"collections": "收藏",
|
||||
"reading-lists": "阅读清单",
|
||||
"reading-lists": "阅读列表",
|
||||
"bookmarks": "书签",
|
||||
"filter-label": "{{common.filter}}",
|
||||
"all-series": "所有系列",
|
||||
@ -789,7 +789,7 @@
|
||||
"manage-collection-label": "管理收藏",
|
||||
"manage-collection-tooltip": "是否允许Kavita根据ComicInfo.xml/opf文件中的SeriesGroup标签创建收藏",
|
||||
"manage-reading-list-label": "管理阅读列表",
|
||||
"manage-reading-list-tooltip": "是否允许Kavita根据ComicInfo.xml/opf文件中的StoryArc/StoryArcNumber和AlternativeSeries/AlternativeCount标签创建阅读清单",
|
||||
"manage-reading-list-tooltip": "是否允许Kavita根据ComicInfo.xml/opf文件中的StoryArc/StoryArcNumber和AlternativeSeries/AlternativeCount标签创建阅读列表",
|
||||
"allow-scrobbling-label": "允许Scrobbling",
|
||||
"allow-scrobbling-tooltip": "是否允许Kavita将阅读事件、想读状态、评分和评论记录至已配置的Scrobble服务提供商?本功能仅在激活服务器的Kavita+订阅后才会生效。",
|
||||
"folder-watching-label": "监控文件夹",
|
||||
@ -917,8 +917,9 @@
|
||||
},
|
||||
"entity-title": {
|
||||
"special": "特刊",
|
||||
"issue-num": "期 #",
|
||||
"chapter": "章节"
|
||||
"issue-num": "{{common.issue-hash-num}}",
|
||||
"chapter": "{{common.chapter-num}}",
|
||||
"book-num": "{{common.book-num-shorthand}}"
|
||||
},
|
||||
"external-series-card": {
|
||||
"open-external": "打开外部链接"
|
||||
@ -954,7 +955,7 @@
|
||||
"gmail-label": "Gmail",
|
||||
"outlook-label": "Outlook",
|
||||
"setting-description": "您必须填写主机名和 SMTP 设置才能使用 Kavita 中的基于电子邮件的功能。",
|
||||
"test-warning": "使用测试按钮之前必须保存。"
|
||||
"test-warning": "在點擊“測試”之前,您必須具有有效的設定。"
|
||||
},
|
||||
"manage-library": {
|
||||
"title": "资料库",
|
||||
@ -1219,9 +1220,9 @@
|
||||
"bulk-select-label": "批量选择项目"
|
||||
},
|
||||
"reading-lists": {
|
||||
"title": "阅读清单",
|
||||
"title": "阅读列表",
|
||||
"item-count": "{{common.item-count}}",
|
||||
"no-data": "没有阅读清单。",
|
||||
"no-data": "没有阅读列表。",
|
||||
"create-one-part-1": "尝试创建",
|
||||
"create-one-part-2": "一个"
|
||||
},
|
||||
@ -1272,7 +1273,7 @@
|
||||
"tags": "标签",
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
"libraries": "资料库",
|
||||
"reading-lists": "阅读清单",
|
||||
"reading-lists": "阅读列表",
|
||||
"collections": "收藏",
|
||||
"close": "{{common.close}}",
|
||||
"loading": "{{common.loading}}",
|
||||
@ -1295,17 +1296,17 @@
|
||||
"close": "{{common.close}}"
|
||||
},
|
||||
"add-to-list-modal": {
|
||||
"title": "添加到阅读清单",
|
||||
"title": "添加到阅读列表",
|
||||
"close": "{{common.close}}",
|
||||
"filter-label": "{{common.filter}}",
|
||||
"promoted-alt": "{{common.promoted}}",
|
||||
"no-data": "尚未创建任何清单",
|
||||
"no-data": "尚未创建任何列表",
|
||||
"loading": "{{common.loading}}",
|
||||
"reading-list-label": "阅读清单",
|
||||
"reading-list-label": "阅读列表",
|
||||
"create": "{{common.create}}"
|
||||
},
|
||||
"edit-reading-list-modal": {
|
||||
"title": "编辑阅读清单: {{name}}",
|
||||
"title": "编辑阅读列表: {{name}}",
|
||||
"general-tab": "{{tabs.general-tab}}",
|
||||
"cover-image-tab": "{{tabs.cover-tab}}",
|
||||
"close": "{{common.close}}",
|
||||
@ -1645,7 +1646,7 @@
|
||||
"email-service-reset": "电子邮件服务已重置",
|
||||
"email-service-reachable": "Kavita电子邮件服务连接成功",
|
||||
"email-service-unresponsive": "电子邮件服务的网址没有响应。",
|
||||
"refresh-covers-queued": "已为{{name}}排队刷新封面",
|
||||
"refresh-covers-queued": "刷新 {{name}} 队列中的封面",
|
||||
"library-file-analysis-queued": "已为{{name}}排队进行资料库文件分析",
|
||||
"entity-read": "{{name}}已标记为已读",
|
||||
"entity-unread": "{{name}}已标记为未读",
|
||||
@ -1713,13 +1714,13 @@
|
||||
"confirm-delete-theme": "删除该主题将从磁盘中删除它。您可以在删除之前从临时目录中获取它",
|
||||
"mal-token-required": "需要 MAL 令牌,在用户设置中设置",
|
||||
"reading-lists-deleted": "阅读列表已删除",
|
||||
"reading-lists-unpromoted": "未推广的阅读清单",
|
||||
"reading-lists-unpromoted": "未推广的阅读列表",
|
||||
"confirm-delete-reading-lists": "您确定要删除阅读列表吗?此操作无法撤消。",
|
||||
"reading-lists-promoted": "推广阅读清单",
|
||||
"reading-list-promoted": "提升阅读清单",
|
||||
"reading-list-unpromoted": "阅读清单未推广",
|
||||
"reading-lists-promoted": "推广阅读列表",
|
||||
"reading-list-promoted": "提升阅读列表",
|
||||
"reading-list-unpromoted": "阅读列表未推广",
|
||||
"confirm-reset-server-settings": "这会将您的设置重置为首次安装值。您确定要继续吗?",
|
||||
"generate-colorscape-queued": "为 {{name}} 生成排队的彩色图案",
|
||||
"generate-colorscape-queued": "为 {{name}} 生成排队的色彩主题",
|
||||
"volume-deleted": "卷已删除",
|
||||
"confirm-delete-chapter": "您确定要删除此章节吗?它不会修改磁盘上的文件。",
|
||||
"confirm-delete-volume": "您确定要删除此卷吗?它不会修改磁盘上的文件。",
|
||||
@ -1739,7 +1740,7 @@
|
||||
"remove-from-want-to-read": "从想读中移除",
|
||||
"remove-from-on-deck": "从最近阅读中移除",
|
||||
"others": "其他",
|
||||
"add-to-reading-list": "添加到阅读清单",
|
||||
"add-to-reading-list": "添加到阅读列表",
|
||||
"add-to-collection": "添加到收藏",
|
||||
"send-to": "发送到",
|
||||
"delete": "删除",
|
||||
@ -1757,7 +1758,7 @@
|
||||
"promote": "推广",
|
||||
"unpromote": "取消推广",
|
||||
"new-collection": "新收藏",
|
||||
"generate-colorscape": "生成彩色图案",
|
||||
"generate-colorscape": "生成色彩主题",
|
||||
"multiple-selections": "多项选择",
|
||||
"scan-library-tooltip": "扫描库以查看是否有更改。使用强制扫描检查每个文件夹",
|
||||
"edit-tooltip": "编辑设置或详细信息",
|
||||
@ -1777,7 +1778,7 @@
|
||||
"promote-tooltip": "使项目对所有用户可见",
|
||||
"settings-tooltip": "查看设置或详细信息",
|
||||
"analyze-files-tooltip": "分析文件的扩展类型和大小",
|
||||
"generate-colorscape-tooltip": "生成色彩图案和任何缺失的封面",
|
||||
"generate-colorscape-tooltip": "生成色彩主题和任何缺失的封面",
|
||||
"refresh-covers-tooltip": "重新生成所有封面",
|
||||
"mark-as-unread-tooltip": "将进度标记为未读",
|
||||
"add-to-want-to-read-tooltip": "添加系列到想读",
|
||||
@ -1814,7 +1815,7 @@
|
||||
"pdf-vertical": "垂直滚动",
|
||||
"pdf-horizontal": "水平滚动",
|
||||
"pdf-page": "点击翻页",
|
||||
"pdf-none": "没有",
|
||||
"pdf-none": "无",
|
||||
"pdf-light": "明亮",
|
||||
"pdf-multiple": "默认",
|
||||
"pdf-dark": "黑暗",
|
||||
@ -1892,7 +1893,7 @@
|
||||
"characters": "{{metadata-fields.characters-title}}",
|
||||
"collection-tags": "收藏标签",
|
||||
"colorist": "上色师",
|
||||
"cover-artist": "封面设计",
|
||||
"cover-artist": "{{person-role-pipe.cover-artist}}",
|
||||
"editor": "编辑",
|
||||
"formats": "格式",
|
||||
"genres": "{{metadata-fields.genres-title}}",
|
||||
@ -2164,7 +2165,7 @@
|
||||
"user-stats": "状态",
|
||||
"theme": "主题",
|
||||
"customize": "自定义",
|
||||
"cbl-import": "CBL 阅读清单",
|
||||
"cbl-import": "CBL 阅读列表",
|
||||
"mal-stack-import": "MAL Stack",
|
||||
"info-section-title": "信息"
|
||||
},
|
||||
|
@ -29,6 +29,7 @@ import {provideTranslocoPersistTranslations} from "@jsverse/transloco-persist-tr
|
||||
import {LazyLoadImageModule} from "ng-lazyload-image";
|
||||
import {getSaver, SAVER} from "./app/_providers/saver.provider";
|
||||
import {distinctUntilChanged} from "rxjs/operators";
|
||||
import {APP_BASE_HREF, PlatformLocation} from "@angular/common";
|
||||
|
||||
const disableAnimations = !('animate' in document.documentElement);
|
||||
|
||||
@ -115,6 +116,10 @@ const translocoOptions = {
|
||||
} as TranslocoConfig
|
||||
};
|
||||
|
||||
function getBaseHref(platformLocation: PlatformLocation): string {
|
||||
return platformLocation.getBaseHrefFromDOM();
|
||||
}
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [
|
||||
importProvidersFrom(BrowserModule,
|
||||
@ -149,6 +154,11 @@ bootstrapApplication(AppComponent, {
|
||||
preLoad,
|
||||
Title,
|
||||
{ provide: SAVER, useFactory: getSaver },
|
||||
{
|
||||
provide: APP_BASE_HREF,
|
||||
useFactory: getBaseHref,
|
||||
deps: [PlatformLocation]
|
||||
},
|
||||
provideHttpClient(withInterceptorsFromDi())
|
||||
]
|
||||
} as ApplicationConfig)
|
||||
|
19
openapi.json
19
openapi.json
@ -2,7 +2,7 @@
|
||||
"openapi": "3.0.1",
|
||||
"info": {
|
||||
"title": "Kavita",
|
||||
"description": "Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v0.8.2.12",
|
||||
"description": "Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v0.8.3.2",
|
||||
"license": {
|
||||
"name": "GPL-3.0",
|
||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||
@ -4383,6 +4383,15 @@
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pageNumber",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -16084,7 +16093,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"maxLength": 32,
|
||||
"maxLength": 256,
|
||||
"minLength": 6,
|
||||
"type": "string"
|
||||
},
|
||||
@ -16144,7 +16153,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"maxLength": 32,
|
||||
"maxLength": 256,
|
||||
"minLength": 6,
|
||||
"type": "string"
|
||||
}
|
||||
@ -19134,7 +19143,7 @@
|
||||
"nullable": true
|
||||
},
|
||||
"password": {
|
||||
"maxLength": 32,
|
||||
"maxLength": 256,
|
||||
"minLength": 6,
|
||||
"type": "string"
|
||||
}
|
||||
@ -19273,7 +19282,7 @@
|
||||
"description": "The Username of the User"
|
||||
},
|
||||
"password": {
|
||||
"maxLength": 32,
|
||||
"maxLength": 256,
|
||||
"minLength": 6,
|
||||
"type": "string",
|
||||
"description": "The new password"
|
||||
|
Loading…
x
Reference in New Issue
Block a user