From ac47cbd75f5cf09a9cf7d0a564c15dc60cc455fa Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Wed, 27 Nov 2024 11:04:18 -0600 Subject: [PATCH 1/4] v0.8.4.1 - Hotfix (#3419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Weblate (bot) Co-authored-by: Adam Beneš Co-authored-by: Dark77 Co-authored-by: Frozehunter Co-authored-by: Havokdan Co-authored-by: Yoan Jacquemin Co-authored-by: aleixcox <18121624@qq.com> Co-authored-by: mag37 --- API.Tests/Parsing/ParsingTests.cs | 11 ++ API/API.csproj | 2 +- API/Controllers/LibraryController.cs | 66 +++++++++-- API/Controllers/ReaderController.cs | 2 + .../ManualMigrations/MigrateChapterRange.cs | 3 +- API/Entities/Chapter.cs | 30 +++-- API/Entities/Volume.cs | 8 +- API/Extensions/ChapterListExtensions.cs | 2 +- API/Services/BookService.cs | 2 +- API/Services/DirectoryService.cs | 2 +- .../Tasks/Scanner/ParseScannedFiles.cs | 4 +- API/Services/Tasks/Scanner/Parser/Parser.cs | 15 ++- UI/Web/src/app/_services/library.service.ts | 7 ++ .../actionable-modal.component.ts | 4 +- .../manage-library.component.ts | 25 ++-- .../_components/dashboard.component.ts | 2 +- UI/Web/src/assets/langs/cs.json | 2 +- UI/Web/src/assets/langs/de.json | 2 +- UI/Web/src/assets/langs/en.json | 3 +- UI/Web/src/assets/langs/fr.json | 4 +- UI/Web/src/assets/langs/pt_BR.json | 12 +- UI/Web/src/assets/langs/sk.json | 109 +++++++++--------- UI/Web/src/assets/langs/sv.json | 85 ++++++++++++-- UI/Web/src/assets/langs/zh_Hans.json | 24 ++-- 24 files changed, 299 insertions(+), 127 deletions(-) diff --git a/API.Tests/Parsing/ParsingTests.cs b/API.Tests/Parsing/ParsingTests.cs index 4fd2f1350e..a3a49762d0 100644 --- a/API.Tests/Parsing/ParsingTests.cs +++ b/API.Tests/Parsing/ParsingTests.cs @@ -1,5 +1,6 @@ using System.Globalization; using System.Linq; +using System.Runtime.InteropServices; using Xunit; using static API.Services.Tasks.Scanner.Parser.Parser; @@ -15,6 +16,16 @@ public void ShouldWork() Assert.Equal(6.5f, a); } + // [Theory] + // [InlineData("de-DE")] + // [InlineData("en-US")] + // public void ShouldParse(string culture) + // { + // var s = 6.5f + ""; + // var a = float.Parse(s, CultureInfo.CreateSpecificCulture(culture)); + // Assert.Equal(6.5f, a); + // } + [Theory] [InlineData("Joe Shmo, Green Blue", "Joe Shmo, Green Blue")] [InlineData("Shmo, Joe", "Shmo, Joe")] diff --git a/API/API.csproj b/API/API.csproj index c0b4a51121..0c9aae8404 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -96,7 +96,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API/Controllers/LibraryController.cs b/API/Controllers/LibraryController.cs index dcb35298e2..34b81c20bf 100644 --- a/API/Controllers/LibraryController.cs +++ b/API/Controllers/LibraryController.cs @@ -20,6 +20,7 @@ using AutoMapper; using EasyCaching.Core; using Hangfire; +using Kavita.Common; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -447,12 +448,58 @@ public async Task ScanFolder(ScanFolderDto dto) return Ok(); } + /// + /// Deletes the library and all series within it. + /// + /// This does not touch any files + /// + /// [Authorize(Policy = "RequireAdminRole")] [HttpDelete("delete")] public async Task> DeleteLibrary(int libraryId) + { + _logger.LogInformation("Library {LibraryId} is being deleted by {UserName}", libraryId, User.GetUsername()); + + try + { + return Ok(await DeleteLibrary(libraryId, User.GetUserId())); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + + /// + /// Deletes multiple libraries and all series within it. + /// + /// This does not touch any files + /// + /// + [Authorize(Policy = "RequireAdminRole")] + [HttpDelete("delete-multiple")] + public async Task> DeleteMultipleLibraries([FromQuery] List libraryIds) { var username = User.GetUsername(); - _logger.LogInformation("Library {LibraryId} is being deleted by {UserName}", libraryId, username); + _logger.LogInformation("Libraries {LibraryIds} are being deleted by {UserName}", libraryIds, username); + + foreach (var libraryId in libraryIds) + { + try + { + await DeleteLibrary(libraryId, User.GetUserId()); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + + return Ok(); + } + + private async Task DeleteLibrary(int libraryId, int userId) + { var series = await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(libraryId); var seriesIds = series.Select(x => x.Id).ToArray(); var chapterIds = @@ -463,16 +510,19 @@ public async Task> DeleteLibrary(int libraryId) if (TaskScheduler.HasScanTaskRunningForLibrary(libraryId)) { _logger.LogInformation("User is attempting to delete a library while a scan is in progress"); - return BadRequest(await _localizationService.Translate(User.GetUserId(), "delete-library-while-scan")); + throw new KavitaException(await _localizationService.Translate(userId, "delete-library-while-scan")); } var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId); - if (library == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "library-doesnt-exist")); + if (library == null) + { + throw new KavitaException(await _localizationService.Translate(userId, "library-doesnt-exist")); + } + // Due to a bad schema that I can't figure out how to fix, we need to erase all RelatedSeries before we delete the library // Aka SeriesRelation has an invalid foreign key - foreach (var s in await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id, - SeriesIncludes.Related)) + foreach (var s in await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id, SeriesIncludes.Related)) { s.Relations = new List(); _unitOfWork.SeriesRepository.Update(s); @@ -489,7 +539,7 @@ public async Task> DeleteLibrary(int libraryId) await _libraryCacheProvider.RemoveByPrefixAsync(CacheKey); await _eventHub.SendMessageAsync(MessageFactory.SideNavUpdate, - MessageFactory.SideNavUpdateEvent(User.GetUserId()), false); + MessageFactory.SideNavUpdateEvent(userId), false); if (chapterIds.Any()) { @@ -508,13 +558,13 @@ await _eventHub.SendMessageAsync(MessageFactory.SeriesRemoved, await _eventHub.SendMessageAsync(MessageFactory.LibraryModified, MessageFactory.LibraryModifiedEvent(libraryId, "delete"), false); - return Ok(true); + return true; } catch (Exception ex) { _logger.LogError(ex, "There was a critical issue. Please try again"); await _unitOfWork.RollbackAsync(); - return Ok(false); + return false; } } diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index b17afa8148..d4bc8a1fe7 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -540,6 +540,8 @@ public async Task MarkMultipleSeriesAsUnread(MarkMultipleSeriesAsR public async Task> GetProgress(int chapterId) { var progress = await _unitOfWork.AppUserProgressRepository.GetUserProgressDtoAsync(chapterId, User.GetUserId()); + _logger.LogDebug("Get Progress for {ChapterId} is {Pages}", chapterId, progress?.PageNum ?? 0); + if (progress == null) return Ok(new ProgressDto() { PageNum = 0, diff --git a/API/Data/ManualMigrations/MigrateChapterRange.cs b/API/Data/ManualMigrations/MigrateChapterRange.cs index cd078699fb..f50cd2e2e5 100644 --- a/API/Data/ManualMigrations/MigrateChapterRange.cs +++ b/API/Data/ManualMigrations/MigrateChapterRange.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using API.Entities; +using API.Extensions; using API.Helpers.Builders; using API.Services.Tasks.Scanner.Parser; using Kavita.Common.EnvironmentInfo; @@ -28,7 +29,7 @@ public static async Task Migrate(DataContext dataContext, IUnitOfWork unitOfWork var chapters = await dataContext.Chapter.ToListAsync(); foreach (var chapter in chapters) { - if (Parser.MinNumberFromRange(chapter.Range) == 0.0f) + if (Parser.MinNumberFromRange(chapter.Range).Is(0.0f)) { chapter.Range = chapter.GetNumberTitle(); } diff --git a/API/Entities/Chapter.cs b/API/Entities/Chapter.cs index 60228ab9f0..a00f315c36 100644 --- a/API/Entities/Chapter.cs +++ b/API/Entities/Chapter.cs @@ -192,22 +192,32 @@ public void UpdateFrom(ParserInfo info) /// public string GetNumberTitle() { - if (MinNumber.Is(MaxNumber)) + // BUG: TODO: On non-english locales, for floats, the range will be 20,5 but the NumberTitle will return 20.5 + // Have I fixed this with TryParse CultureInvariant + try { - if (MinNumber.Is(Parser.DefaultChapterNumber) && IsSpecial) + if (MinNumber.Is(MaxNumber)) { - return Parser.RemoveExtensionIfSupported(Title); - } + if (MinNumber.Is(Parser.DefaultChapterNumber) && IsSpecial) + { + return Parser.RemoveExtensionIfSupported(Title); + } - if (MinNumber.Is(0) && !float.TryParse(Range, CultureInfo.InvariantCulture, out _)) - { - return $"{Range}"; - } + if (MinNumber.Is(0f) && !float.TryParse(Range, CultureInfo.InvariantCulture, out _)) + { + return $"{Range.ToString(CultureInfo.InvariantCulture)}"; + } - return $"{MinNumber}"; + return $"{MinNumber.ToString(CultureInfo.InvariantCulture)}"; + } + + return $"{MinNumber.ToString(CultureInfo.InvariantCulture)}-{MaxNumber.ToString(CultureInfo.InvariantCulture)}"; + } + catch (Exception) + { + return MinNumber.ToString(CultureInfo.InvariantCulture); } - return $"{MinNumber}-{MaxNumber}"; } /// diff --git a/API/Entities/Volume.cs b/API/Entities/Volume.cs index a5badccf74..5338494e65 100644 --- a/API/Entities/Volume.cs +++ b/API/Entities/Volume.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using API.Entities.Interfaces; using API.Extensions; using API.Services.Tasks.Scanner.Parser; @@ -67,11 +68,12 @@ public class Volume : IEntityDate, IHasReadTimeEstimate, IHasCoverImage /// public string GetNumberTitle() { - if (MinNumber.Is(MaxNumber)) + if (MinNumber.Equals(MaxNumber)) { - return $"{MinNumber}"; + return MinNumber.ToString(CultureInfo.InvariantCulture); } - return $"{MinNumber}-{MaxNumber}"; + + return $"{MinNumber.ToString(CultureInfo.InvariantCulture)}-{MaxNumber.ToString(CultureInfo.InvariantCulture)}"; } public void ResetColorScape() diff --git a/API/Extensions/ChapterListExtensions.cs b/API/Extensions/ChapterListExtensions.cs index 83e6880c48..5456a6e16a 100644 --- a/API/Extensions/ChapterListExtensions.cs +++ b/API/Extensions/ChapterListExtensions.cs @@ -38,7 +38,7 @@ public static class ChapterListExtensions fakeChapter.UpdateFrom(info); return specialTreatment ? chapters.FirstOrDefault(c => c.Range == Parser.RemoveExtensionIfSupported(info.Filename) || c.Files.Select(f => Parser.NormalizePath(f.FilePath)).Contains(normalizedPath)) - : chapters.FirstOrDefault(c => c.Range == fakeChapter.GetNumberTitle()); // BUG: TODO: On non-english locales, for floats, the range will be 20,5 but the NumberTitle will return 20.5 + : chapters.FirstOrDefault(c => c.Range == fakeChapter.GetNumberTitle()); } /// diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs index e4ed920473..740227af88 100644 --- a/API/Services/BookService.cs +++ b/API/Services/BookService.cs @@ -885,7 +885,7 @@ public async Task> CreateKeyToPageMappingAsync(EpubBookR } /// - /// Extracts a pdf into images to a target directory. Uses multi-threaded implementation since docnet is slow normally. + /// Extracts a pdf into images to a target directory. Uses multithreaded implementation since docnet is slow normally. /// /// /// diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 696418c77d..338ea0537a 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -708,7 +708,7 @@ public IEnumerable GetAllDirectories(string folderPath, GlobMatcher? mat if (!FileSystem.Directory.Exists(folderPath)) return ImmutableArray.Empty; var directories = new List(); - var foundDirs = GetDirectories(folderPath); + var foundDirs = GetDirectories(folderPath, matcher); foreach (var foundDir in foundDirs) { directories.Add(foundDir); diff --git a/API/Services/Tasks/Scanner/ParseScannedFiles.cs b/API/Services/Tasks/Scanner/ParseScannedFiles.cs index 994daee80a..f4405165d7 100644 --- a/API/Services/Tasks/Scanner/ParseScannedFiles.cs +++ b/API/Services/Tasks/Scanner/ParseScannedFiles.cs @@ -818,11 +818,11 @@ private static void UpdateSortOrder(ConcurrentDictionary l.id); + if (!await this.confirmService.confirm(translate('toasts.bulk-delete-libraries', {count: libIds.length}))) return; + this.libraryService.deleteMultiple(libIds) + .pipe(catchError((_, obs) => { + this.resetBulkMode(); + return obs; + })) + .subscribe(() => { + this.getLibraries(); + this.resetBulkMode(); + }) + break; case Action.CopySettings: // Remove the source library from the list if (selected.length === 1 && selected[0].id === this.sourceCopyToLibrary!.id) { diff --git a/UI/Web/src/app/dashboard/_components/dashboard.component.ts b/UI/Web/src/app/dashboard/_components/dashboard.component.ts index efb3b2290e..2f8bc4dcaa 100644 --- a/UI/Web/src/app/dashboard/_components/dashboard.component.ts +++ b/UI/Web/src/app/dashboard/_components/dashboard.component.ts @@ -233,7 +233,7 @@ export class DashboardComponent implements OnInit { const filter = this.filterUtilityService.createSeriesV2Filter(); filter.statements.push({field: FilterField.ReadProgress, comparison: FilterComparison.GreaterThan, value: '0'}); - filter.statements.push({field: FilterField.ReadProgress, comparison: FilterComparison.LessThan, value: '100'}); + filter.statements.push({field: FilterField.ReadProgress, comparison: FilterComparison.NotEqual, value: '100'}); if (filter.sortOptions) { filter.sortOptions.sortField = SortField.LastChapterAdded; filter.sortOptions.isAscending = false; diff --git a/UI/Web/src/assets/langs/cs.json b/UI/Web/src/assets/langs/cs.json index 9fc5d6b50c..f745372adc 100644 --- a/UI/Web/src/assets/langs/cs.json +++ b/UI/Web/src/assets/langs/cs.json @@ -12,7 +12,7 @@ "server-settings-link": "Nastavení serveru", "not-granted": "Nebyl vám udělen přístup k žádným knihovnám.", "on-deck-title": "Na palubě", - "recently-updated-title": "Nedávno aktualizovaná řada", + "recently-updated-title": "Nedávno aktualizovaná série", "recently-added-title": "Nově přidaná série", "more-in-genre-title": "Více v {{genre}}" }, diff --git a/UI/Web/src/assets/langs/de.json b/UI/Web/src/assets/langs/de.json index 1f50c061ff..eadf08954e 100644 --- a/UI/Web/src/assets/langs/de.json +++ b/UI/Web/src/assets/langs/de.json @@ -2185,7 +2185,7 @@ "bulk-scan": "Das Scannen mehrerer Bibliotheken wird linear durchgeführt. Je nach Größe der Bibliothek kann dies sehr lange dauern und nicht vollständig sein.", "bulk-covers": "Das Aktualisieren von Titelseiten in mehreren Bibliotheken ist intensiv und kann lange dauern. Bist du sicher, dass du fortfahren willst?", "person-image-downloaded": "Personen Cover wurde heruntergeladen und angewendet.", - "confirm-delete-multiple-chapters": "Möchten Sie wirklich {{count}} Kapitel/Bände löschen? Dateien auf der Festplatte werden dadurch nicht verändert." + "confirm-delete-multiple-chapters": "Sind Sie sicher, dass Sie {{count}} Kapitel/Bände löschen möchten? Die Dateien auf der Festplatte werden dadurch nicht verändert." }, "read-time-pipe": { "less-than-hour": "<1 Stunde", diff --git a/UI/Web/src/assets/langs/en.json b/UI/Web/src/assets/langs/en.json index 9ccf35c337..6b4e9fd2b8 100644 --- a/UI/Web/src/assets/langs/en.json +++ b/UI/Web/src/assets/langs/en.json @@ -2433,7 +2433,8 @@ "must-select-library": "At least one library must be selected", "bulk-scan": "Scanning multiple libraries will be done linearly. This may take a long time and not complete depending on library size.", "bulk-covers": "Refreshing covers on multiple libraries is intensive and can take a long time. Are you sure you want to continue?", - "person-image-downloaded": "Person cover was downloaded and applied." + "person-image-downloaded": "Person cover was downloaded and applied.", + "bulk-delete-libraries": "Are you sure you want to delete {{count}} libraries?" }, "read-time-pipe": { diff --git a/UI/Web/src/assets/langs/fr.json b/UI/Web/src/assets/langs/fr.json index 594b11c457..1968a77dbf 100644 --- a/UI/Web/src/assets/langs/fr.json +++ b/UI/Web/src/assets/langs/fr.json @@ -2185,7 +2185,7 @@ "bulk-covers": "Rafraichir les couvertures pour plusieurs bibliothèques est lourd pour le serveur et peut prendre longtemps. Êtes vous sûr de vouloir continuer ?", "must-select-library": "Au moins une bibliothèque doit être sélectionnée", "person-image-downloaded": "La couverture de la personne a été téléchargée et appliquée.", - "confirm-delete-multiple-chapters": "Etes-vous sûr de vouloir supprimer {{count}} chapitre/volume ? Cela ne modifiera pas les fichiers sur le disque." + "confirm-delete-multiple-chapters": "Etes-vous sûr de vouloir supprimer {{count}} chapitres/volumes ? Cela ne modifiera pas les fichiers sur le disque." }, "read-time-pipe": { "less-than-hour": "<1 Heure", @@ -2209,7 +2209,7 @@ "mark-as-read-tooltip": "Marquer comme entièrement lu", "mark-as-unread": "Marquer comme non lu", "mark-as-unread-tooltip": "Marquer comme non lu", - "scan-series": "Scanner les séries", + "scan-series": "Scanner la/les série(s)", "scan-series-tooltip": "Rechercher des modifications dans les séries", "add-to": "Ajouter à", "add-to-want-to-read": "Ajouter à la liste des envies", diff --git a/UI/Web/src/assets/langs/pt_BR.json b/UI/Web/src/assets/langs/pt_BR.json index 8eabee3900..1df4fc831b 100644 --- a/UI/Web/src/assets/langs/pt_BR.json +++ b/UI/Web/src/assets/langs/pt_BR.json @@ -301,7 +301,7 @@ "token-valid": "Token Válido", "token-expired": "Token Expirado", "no-token-set": "Nenhum Token Definido", - "token-set": "Definir Token", + "token-set": "Token Definido", "generate": "Gerar", "generic-instructions": "Preencha informações sobre os diferentes Serviços Externos que você precisa para permitir que Kavita+ interaja com eles.", "instructions": "First time users should click on \"{{scrobbling-providers.generate}}\" below to allow Kavita+ to talk with {{service}}. Once you authorize the program, copy and paste the token in the input below. You can regenerate your token at any time.", @@ -1716,7 +1716,7 @@ "last-scanned-title": "Último Escaneamento", "folder-path-title": "Caminho da Pasta", "folder-path-tooltip": "Caminho mais alto da raiz da biblioteca que contém todos os arquivos da série", - "lowest-folder-path-title": "Caminho de Pasta Mais Baixo", + "lowest-folder-path-title": "Caminho de Pasta Mais Baixa", "lowest-folder-path-tooltip": "Caminho mais baixo da raiz da biblioteca que contém todos os arquivos da série", "publication-status-title": "Situação da Publicação", "total-pages-title": "Total de Páginas", @@ -1818,7 +1818,7 @@ "cover-image-description": "{{edit-series-modal.cover-image-description}}" }, "day-breakdown": { - "title": "Divisão do Dia", + "title": "Divisão por Dia", "no-data": "Sem progresso, comece a ler", "x-axis-label": "Dia da Semana", "y-axis-label": "Eventos de Leitura" @@ -2105,7 +2105,7 @@ "email-service-reachable": "Conexão de e-mail Kavita bem-sucedida", "email-service-unresponsive": "O URL do serviço de e-mail não respondeu.", "refresh-covers-queued": "Atualizar capas na fila para {{name}}", - "generate-colorscape-queued": "Gerar colorscape na fila para {{name}}", + "generate-colorscape-queued": "Gerar paisagem de cores na fila para {{name}}", "library-file-analysis-queued": "Análise de arquivo de biblioteca na fila para {{name}}", "entity-read": "{{name}} agora é lido", "entity-unread": "{{name}} agora é não lido", @@ -2197,8 +2197,8 @@ "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", "refresh-covers": "Atualizar Capas", "refresh-covers-tooltip": "Regenerar todas as capas", - "generate-colorscape": "Gerar ColorScape", - "generate-colorscape-tooltip": "Gerar colorscapes e quaisquer capas ausentes", + "generate-colorscape": "Gerar Paisagem de Cores", + "generate-colorscape-tooltip": "Gerar paisagem de cores e quaisquer capas ausentes", "analyze-files": "Analisar Arquivos", "analyze-files-tooltip": "Analisar Arquivos quanto ao tipo e tamanho da extensão", "settings": "Configurações", diff --git a/UI/Web/src/assets/langs/sk.json b/UI/Web/src/assets/langs/sk.json index 15ab20a589..f36436dc91 100644 --- a/UI/Web/src/assets/langs/sk.json +++ b/UI/Web/src/assets/langs/sk.json @@ -8,11 +8,11 @@ "submit": "Prihlásiť sa" }, "dashboard": { - "no-libraries": "Momentálne nie sú vytvorené žiadne knižnice. Vytvorte ich v", + "no-libraries": "Momentálne nie sú vytvorené žiadne knižnice. Vytvorte nejaké v", "server-settings-link": "Nastavenia servera", "not-granted": "Nemáte prístup do žiadnej z knižníc.", "on-deck-title": "Pokračovať v čítaní", - "recently-updated-title": "Naposledy aktualizované série", + "recently-updated-title": "Naposledy aktualizované Série", "recently-added-title": "Novo pridané série", "more-in-genre-title": "Viac v {{genre}}" }, @@ -146,7 +146,7 @@ "line-height-book-tooltip": "Koľko medzier medzi riadkami knihy", "margin-book-label": "Okraj stránky", "margin-book-tooltip": "Koľko medzier na každej strane obrazovky. Na mobilných zariadeniach sa to prepíše na 0 bez ohľadu na toto nastavenie.", - "clients-opds-description": "Všetci klienti tretích strán budú používať kľúč API alebo pripájaciu adresu URL nižšie. Sú to ako heslá, uchovávajte ich v súkromí.", + "clients-opds-description": "Všetci klienti tretích strán budú používať kľúč API alebo pripájaciu adresu URL nižšie. Musí sa s nimi zaobchádzať dôverne, rovnako ako s heslami.", "clients-api-key-tooltip": "Kľúč API je ako heslo. Jeho obnovenie zruší platnosť všetkých existujúcich klientov.", "reset": "{{common.reset}}", "save": "{{common.save}}", @@ -188,7 +188,7 @@ "add": "{{common.add}}", "default-theme": "Predvolené", "active-theme": "Aktívne", - "description": "Kavita prichádza v mojich farbách, nájdite si farebnú schému, ktorá vyhovuje vašim potrebám alebo si ju vytvorte sami a zdieľajte ju. Motívy môžu byť použité pre váš účet alebo pre všetky účty.", + "description": "Kavita prichádza vo svojich farbách, nájdite si farebnú schému, ktorá vyhovuje vašim potrebám alebo si ju vytvorte sami a zdieľajte ju. Motívy môžu byť použité pre váš účet alebo pre všetky účty.", "downloaded": "Stiahnuté", "downloadable": "Stiahnuteľné", "preview-default-admin": "Najprv vyberte tému alebo ju nahrajte ručne", @@ -422,7 +422,7 @@ "name-conflict": "Zoznam na čítanie ({{readingListName}}) už existuje vo vašom účte, ktorý sa zhoduje so súborom cbl.", "series-collision": "Séria, {{seriesLink}}, koliduje s inou sériou s rovnakým názvom v inej knižnici.", "series-missing": "Séria {{series}} v Kavite chýba alebo váš účet nemá povolenie. Všetky položky s touto sériou budú z importu vynechané.", - "volume-missing": "{{series}}: zväzok {{volume}} chýba v Kavite alebo váš účet nemá povolenie. Všetky položky s týmto číslom zväzku budú preskočené.", + "volume-missing": "{{series}}: Zväzok {{volume}} chýba v Kavite alebo váš účet nemá povolenie. Všetky položky s týmto číslom zväzku budú preskočené.", "all-chapter-missing": "Všetky kapitoly nemožno priradiť ku kapitolám v Kavite.", "invalid-file": "Súbor je poškodený alebo nezodpovedá očakávaným značkám/špecifikáciám.", "success": "{{series}} zväzok {{volume}} kapitola {{chapter}} úspešne zmapovaná." @@ -569,11 +569,11 @@ "invite-user": { "title": "Pozvať používateľa", "close": "{{common.close}}", - "description": "Pozvite používateľa na svoj server zadaním jeho e-mailu. Dostanú e-mail na vytvorenie účtu. Aby to fungovalo, musíte mať nastavené polia Host Name a Email na karte E-mail, inak sa vám zobrazí odkaz na nastavenie v mene používateľa.

E-mail nemusí byť platný.", + "description": "Pozvite používateľa na svoj server zadaním jeho e-mailu. Dostanú e-mail na vytvorenie účtu. Aby to fungovalo, musíte mať nastavené polia Host Name a Email na karte Email, inak sa vám zobrazí odkaz na nastavenie v mene používateľa.

E-mail nemusí byť platný.", "email": "{{common.email}}", "required-field": "{{common.required-field}}", "setup-user-title": "Používateľ bol pozvaný", - "setup-user-description": "Na nastavenie účtu pre svojho používateľa môžete použiť nasledujúci odkaz nižšie alebo použiť tlačidlo kopírovania. Pred použitím odkazu na registráciu nového používateľa sa možno budete musieť odhlásiť. Ak Kavita dokáže určiť váš server ako prístupný externe (alebo je nastavený názov hostiteľa), používateľovi bude odoslaný e-mail a tieto odkazy môže použiť na dokončenie nastavenia svojho účtu. V opačnom prípade použite odkaz nižšie alebo v protokoloch na manuálne odoslanie alebo nastavenie ich účtu.", + "setup-user-description": "Na nastavenie účtu pre svojho používateľa môžete použiť nasledujúci odkaz nižšie alebo použiť tlačidlo kopírovania. Pred použitím odkazu na registráciu nového používateľa sa možno budete musieť odhlásiť.", "setup-user-account": "Nastavte používateľský účet", "setup-user-account-tooltip": "Skopírujte to a vložte na novú kartu. Možno sa budete musieť odhlásiť.", "invite-url-label": "Adresa URL pozvánky", @@ -610,7 +610,7 @@ "discord-validation": "Toto nie je platné ID používateľa Discord. Vaše ID používateľa nie je vaše používateľské discord meno.", "activate-delete": "{{common.delete}}", "activate-reset": "{{common.reset}}", - "activate-reset-tooltip": "Uvoľnite licenciu s týmto serverom. Vyžaduje licenciu aj e-mail.", + "activate-reset-tooltip": "Zrušte platnosť predchádzajúcej registrácie pomocou vašej licencie. Vyžaduje licenciu aj e-mail", "activate-save": "{{common.save}}", "help-label": "{{common.help}}", "activate-discordId-label": "Discord Používateľské ID", @@ -689,7 +689,7 @@ "description": "Vyplňte formulár na registráciu účtu správcu", "username-label": "{{common.username}}", "email-label": "{{common.email}}", - "email-tooltip": "E-mail nemusí byť skutočná adresa, ale poskytuje prístup k zabudnutému heslu. Neposiela sa mimo server, pokiaľ sa zabudnuté heslo nepoužije bez vlastného hostiteľa e-mailovej služby.", + "email-tooltip": "E-mail nemusí byť skutočná adresa, ale poskytuje prístup k zabudnutému heslu. Neposiela sa mimo server, pokiaľ vám Kavita nepošle e-mail.", "password-label": "{{common.password}}", "required-field": "{{validation.required-field}}", "valid-email": "{{validation.valid-email}}", @@ -710,7 +710,7 @@ "incognito": "Inkognito", "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": "Upraviť Informácie o Sérii", + "edit-series-alt": "Upraviť informácie", "reviews-tab": "{{tabs.reviews-tab}}", "storyline-tab": "{{tabs.storyline-tab}}", "books-tab": "{{tabs.books-tab}}", @@ -813,7 +813,7 @@ "all-series": "Všetky Série", "clear": "{{common.clear}}", "donate": "Prispieť", - "donate-tooltip": "Môžete to odstrániť prihlásením sa na odber Kavita+", + "donate-tooltip": "Prihlás sa na odber Kavita+ pre odstránenie tohto elementu", "back": "Naspäť", "more": "Viac", "customize": "{{settings.customize}}", @@ -1024,14 +1024,14 @@ "description-part-1": "Táto tabuľka obsahuje problémy zistené počas skenovania alebo čítania vašich médií. Môžete ju kedykoľvek vymazať a na vykonanie analýzy použiť Library (Force) Scan (vynútené skenovanie). Zoznam niektorých bežných chýb a ich význam nájdete na stránke " }, "manage-email-settings": { - "description": "Aby ste mohli používať niektoré funkcie Kavity, ako je Zabudnuté heslo a Odoslať do zariadenia, musí byť nastavený poskytovateľ e-mailu. Ostatné funkcie, ako je zmena hesla, sú bez nastavenia e-mailu menej bezpečné.", + "description": "Aby ste mohli používať niektoré funkcie Kavity, ako je Zabudnuté heslo a Odoslať do zariadenia, musí byť nastavený poskytovateľ e-mailu. Ostatné funkcie, ako zabudnuté heslo, vyžadujú zásah správcu bez nastavenia e-mailu.", "send-to-warning": "Ak chcete, aby funkcia Odoslať do zariadenia fungovala, musíte nastaviť nastavenia e-mailu", "email-url-label": "Adresa URL e-mailovej služby", "email-url-tooltip": "Použite plne kvalifikovanú adresu URL e-mailovej služby. Nezahŕňajte koncovú lomku.", "email-settings-title": "Nastavenia e-mailu", "reset": "{{common.reset}}", "test": "Test", - "host-name-tooltip": "Názov domény (reverzného proxy). Ak je nastavené, generovanie e-mailov sa vždy použije.", + "host-name-tooltip": "Názov domény (reverzného proxy). Vyžaduje sa pre funkčnosť e-mailu. Ak nieje reverzné proxy, použite ľubovoľnú url adresu.", "host-name-validation": "Hostname musí začínať http(s) a nesmie končiť na /", "sender-address-label": "Adresa odosielateľa", "sender-address-tooltip": "Toto je e-mailová adresa, z ktorej príjemca uvidí, keď dostane e-mail. Zvyčajne ide o e-mailovú adresu priradenú k účtu.", @@ -1045,7 +1045,7 @@ "size-limit-label": "Limit veľkosti", "size-limit-tooltip": "Koľko bytov dokáže e-mailový server spracovať pre prílohy", "customized-templates-label": "Prispôsobené šablóny", - "customized-templates-tooltip": "Mala by Kavita používať adresár config/templates pre šablóny namiesto predvoleného adresára? Zodpovedáte za to, aby ste boli informovaní o zmenách šablóny.", + "customized-templates-tooltip": "Mala by Kavita používať adresár config/templates pre šablóny namiesto predvoleného adresára? Zodpovedáte za to, že budete držať krok so zmenami v šablónach.", "reset-to-default": "{{common.reset-to-default}}", "save": "{{common.save}}", "host-name-label": "Meno hostiteľa", @@ -1061,9 +1061,9 @@ "add-library": "Pridať knižnicu", "no-data": "Neexistujú žiadne knižnice. Skúste si nejakú vytvoriť.", "loading": "{{common.loading}}", - "last-scanned-title": "Naposledy skenované:", - "shared-folders-title": "Zdieľané priečinky:", - "type-title": "Typ:", + "last-scanned-title": "Naposledy skenované", + "shared-folders-title": "Priečinky", + "type-title": "Typ", "scan-library": "Skenovať knižnicu", "delete-library": "Zmazať knižnicu", "delete-library-by-name": "Zmazať {{name}}", @@ -1093,7 +1093,7 @@ "encode-as-description-part-2": "Môžem použiť WebP?", "encode-as-description-part-3": "Môžem použiť AVIF?", "encode-as-warning": "Po prechode na WebP/AVIF nemôžete konvertovať späť na PNG. Na obnovenie všetkých obalov budete musieť obnoviť obaly vo svojich knižniciach. Záložky a obľúbené ikony nie je možné konvertovať.", - "media-warning": "Úlohu konverzie médií musíte spustiť na karte Úlohy.,", + "media-warning": "Po uložení musíte spustiť úlohu konverzie médií na karte Úlohy.", "encode-as-label": "Uložiť médiá ako", "encode-as-tooltip": "Všetky médiá, ktoré Kavita spravuje (obálky, záložky, favicony), budú kódované ako tento typ.", "bookmark-dir-label": "Adresár záložiek", @@ -1108,7 +1108,7 @@ "cover-image-size-tooltip": "Aké veľké obrázky by sa mali generovať. Poznámka: Čokoľvek väčšie ako predvolené nastavenie bude mať za následok dlhší čas načítania stránky." }, "manage-scrobble-errors": { - "description": "Táto tabuľka obsahuje problémy zistené počas scrobblingu. Tento zoznam nie je spravovaný. Môžete ho kedykoľvek vymazať a počkať na ďalšie nahranie scrobble. Ak existuje neznáma séria, najlepšie je opraviť názov série alebo lokalizovaný názov série alebo pridať webový odkaz pre poskytovateľov.", + "description": "Táto tabuľka obsahuje problémy zistené počas scrobblingu. Môžete ho kedykoľvek vymazať a počkať na ďalšie nahranie scrobble. Ak existuje neznáma séria, najlepšie je opraviť názov série alebo lokalizovaný názov série alebo pridať webový odkaz pre poskytovateľov.", "filter-label": "{{common.filter}}", "clear-errors": "Vymazať chyby", "series-header": "Série", @@ -1168,7 +1168,7 @@ "ip-address-validation": "Adresy IP môžu obsahovať iba platné adresy IPv4 alebo IPv6", "base-url-validation": "Základná adresa URL musí začínať a končiť znakom /", "opds-label": "OPDS", - "networking-settings-title": "Sieťovanie", + "networking-settings-title": "Pripojenie", "system-settings-title": "Systém", "customization-settings-title": "Prispôsobenie", "port-label": "Port" @@ -1216,7 +1216,7 @@ "bust-cache-task-desc": "Preruší medzipamäť Kavity+, - malo by sa používať iba pri ladení zlých zápasov.", "bust-cache-task-success": "Vyrovnávacia pamäť Kavita+ bola prerušená", "bust-locale-task": "Preruší lokálnu vyrovnávaciu pamäť", - "bust-locale-task-desc": "Preruší lokálnu vyrovnávaciu pamäť. To môže vyriešiť problémy s reťazcami, ktoré sa po aktualizácii nezobrazujú správne", + "bust-locale-task-desc": "Preruší lokálnu vyrovnávaciu pamäť. To môže vyriešiť problémy s reťazcami, ktoré sa po aktualizácii nezobrazujú správne. Vyžaduje sa obnovenie prehliadača.", "bust-locale-task-success": "Lokálna vyrovnávacia pamäť bola prerušená", "clear-reading-cache-task": "Vymazať vyrovnávaciu pamäť čítania", "clear-reading-cache-task-desc": "Vymaže súbory vo vyrovnávacej pamäti na čítanie. Užitočné, keď ste práve aktualizovali súbor, ktorý ste predtým čítali za posledných 24 hodín.", @@ -1325,7 +1325,7 @@ "admin-users": "Používatelia", "admin-statistics": "Štatistiky", "admin-system": "Systém", - "clients": "API Key / OPDS", + "clients": "API kľúč / OPDS", "devices": "Zariadenia", "admin-email": "Email", "admin-tasks": "Úlohy", @@ -1335,7 +1335,7 @@ "admin-logs": "Logy", "theme": "Téma", "customize": "Prispôsobenie", - "cbl-import": "CBL Čítanie Zoznam", + "cbl-import": "CBL Zoznam na čítanie", "mal-stack-import": "MAL Stack", "scrobbling": "Scrobblovanie" }, @@ -1478,7 +1478,7 @@ "ending-title": "Ukončenie", "starting-title": "Začiatok", "promote-label": "Povýšiť", - "promote-tooltip": "Propagácia znamená, že tag možno vidieť na celom serveri, nielen pre správcov. Všetky série, ktoré majú tento tag, budú mať stále obmedzenia prístupu používateľov." + "promote-tooltip": "Propagácia znamená, že kolekciu je možné vidieť na celom serveri, nielen pre vás. Všetky série v rámci tejto kolekcie budú mať stále obmedzenia prístupu používateľov." }, "import-mal-collection-modal": { "close": "{{common.close}}", @@ -1500,8 +1500,8 @@ }, "import-cbl-modal": { "close": "{{common.close}}", - "import-description": "Ak chcete začať, importujte súbor .cbl. Kavita pred importovaním vykoná viacero kontrol. Niektoré kroky budú blokovať postup vpred kvôli problémom so súborom.", - "validate-description": "Všetky súbory boli overené, aby sa zistilo, či je v zozname potrebné vykonať nejaké operácie. Všetky zoznamy, ktoré zlyhali, sa neposunú na ďalší krok. Opravte súbory CBL a skúste to znova.", + "import-description": "Ak chcete začať, importujte súbor \".cbl\". Kavita pred importovaním vykoná viacero kontrol. Niektoré kroky budú blokované kvôli problémom so súborom.", + "validate-description": "Všetky súbory boli overené, aby sa zistilo, či je v zozname potrebné vykonať nejaké operácie. Všetky zoznamy, ktoré zlyhali, sa neposunú do ďalšieho kroku. Opravte súbory CBL a skúste to znova.", "validate-warning": "Existujú problémy s CBL, ktoré bránia importu. Opravte tieto problémy a skúste to znova.", "validate-no-issue-description": "Nenašli sa žiadne problémy s CBL, stlačte Ďalej.", "dry-run-description": "Toto je suchý chod a ukazuje, čo sa stane, ak stlačíte Ďalej a vykonáte import. Všetky zlyhania nebudú importované.", @@ -1614,9 +1614,9 @@ }, "metadata-filter-row": { "unit-reading-date": "Dátum", - "unit-average-rating": "Priemerné hodnotenie (Kavita+) – len pre série uložené vo vyrovnávacej pamäti", + "unit-average-rating": "Externé hodnotenie Kavita+, percent", "unit-reading-progress": "Percent", - "unit-user-rating": "{{metadata-filter-row.unit-reading-progress}}", + "unit-user-rating": "0.0 – 5.0 hviezdičiek", "unit-read-last": "Dni od DNES" }, "sort-field-pipe": { @@ -1671,27 +1671,27 @@ "save": "{{common.save}}", "field-locked-alt": "Pole je zamknuté", "info-title": "Informácie", - "library-title": "Knižnica:", - "format-title": "Formát:", - "created-title": "Vytvorené:", + "library-title": "Knižnica", + "format-title": "Formát", + "created-title": "Vytvorené", "last-read-title": "{{sort-field-pipe.read-progress}}", - "last-added-title": "Posledná pridaná položka:", - "last-scanned-title": "Naposledy skenované:", - "folder-path-title": "Cesta k priečinku:", - "publication-status-title": "Stav publikácie:", - "total-pages-title": "Celkový počet strán:", - "total-items-title": "Celkový počet položiek:", - "max-items-title": "Maximálny počet položiek:", - "size-title": "Veľkosť:", + "last-added-title": "Posledná pridaná položka", + "last-scanned-title": "Naposledy skenované", + "folder-path-title": "Cesta k priečinku", + "publication-status-title": "Stav publikácie", + "total-pages-title": "Celkový počet strán", + "total-items-title": "Celkový počet položiek", + "max-items-title": "Maximálny počet položiek", + "size-title": "Veľkosť", "loading": "{{common.loading}}", - "added-title": "Pridané:", - "last-modified-title": "Naposledy zmenené:", + "added-title": "Pridané", + "last-modified-title": "Naposledy zmenené", "view-files": "Zobraziť súbory", "pages-title": "{{edit-chapter-modal.pages-label}}", - "chapter-title": "Kapitola:", + "chapter-title": "Kapitola", "volume-num": "{{common.volume-num}}", "highest-count-tooltip": "Najvyšší počet nájdený vo všetkých ComicInfo v sérii", - "max-issue-tooltip": "Pole Max Issue alebo Volume zo všetkých ComicInfo v sérii", + "max-issue-tooltip": "Pole Max Vydanie alebo Zväzok zo všetkých ComicInfo v sérii", "force-refresh": "Vynútiť obnovenie", "force-refresh-tooltip": "Vynútiť obnovenie externých metadát z Kavita+", "release-year-validation": "{{validation.year-validation}}", @@ -1870,7 +1870,7 @@ "genres": "{{metadata-fields.genres-title}}", "series-count": "Séria {{num}}", "file-count": "Súbory: {{num}}", - "volume-count": "{{num}} zväzkov" + "volume-count": "{{num}} Zväzkov" }, "errors": { "series-doesnt-exist": "Táto séria už neexistuje", @@ -1878,10 +1878,10 @@ "unknown-crit": "Vyskytla sa neznáma kritická chyba", "user-not-auth": "Používateľ nie je overený", "error-code": "{{num}} Chyba", - "download": "Pri sťahovaní tohto súboru sa vyskytol problém alebo nemáte povolenia", + "download": "Pri sťahovaní tohto súboru sa vyskytol problém alebo nemáte povolenie", "not-found": "Táto adresa URL neexistuje", "generic": "Niečo neočakávané sa pokazilo", - "rejected-cover-upload": "Obrázok sa nepodarilo načítať, pretože server odmietol požiadavku. Namiesto toho stiahnite a nahrajte zo súboru.", + "rejected-cover-upload": "Obrázok sa nepodarilo načítať prostredníctvom url adresy. Namiesto toho stiahnite a nahrajte zo súboru.", "invalid-confirmation-url": "Neplatná potvrdzovacia adresa URL", "invalid-confirmation-email": "Neplatný potvrdzujúci e-mail", "invalid-password-reset-url": "Neplatná adresa URL na obnovenie hesla", @@ -1971,7 +1971,7 @@ "age-rating": "{{metadata-fields.age-rating-title}}", "characters": "{{metadata-fields.characters-title}}", "collection-tags": "Tagy zbierok", - "cover-artist": "{{person-role-pipe.cover-artist}}", + "cover-artist": "{{person-role-pipe.artist}}", "editor": "Editor", "formats": "Formáty", "genres": "{{metadata-fields.genres-title}}", @@ -2071,7 +2071,7 @@ "k+-unlocked": "Kavita+ odomknutá!", "k+-error": "Pri aktivácii vašej licencie sa vyskytla chyba. Prosím skúste znova.", "k+-delete-key": "Týmto sa odstráni iba licenčný kľúč Kavity a umožní sa zobrazenie odkazu na kúpu. Týmto sa vaše predplatné nezruší! Použite to iba na pokyn podpory!", - "k+-reset-key": "Toto odpojí váš kľúč od servera a umožní vám znova zaregistrovať inštanciu Kavita.", + "k+-reset-key": "Toto zruší platnosť predchádzajúcej registrácie pomocou vašej licencie a umožní vám znova zaregistrovať inštanciu Kavita.", "k+-reset-key-success": "Vaša licencia bola zrušená. Pomocou tlačidla Upraviť znova zaregistrujte svoju inštanciu a znova aktivujte Kavita+", "library-deleted": "Knižnica {{name}} bola odstránená", "copied-to-clipboard": "Skopírované do schránky", @@ -2135,7 +2135,8 @@ "generate-colorscape-queued": "Generovať farebnú škálu v poradí pre {{name}}", "volume-deleted": "Zväzok vymazaný", "bulk-covers": "Obnovenie obalov vo viacerých knižniciach je intenzívne a môže trvať dlho. Naozaj chcete pokračovať?", - "person-image-downloaded": "Titulná fotka osoby bola stiahnutá a použitá." + "person-image-downloaded": "Titulná fotka osoby bola stiahnutá a použitá.", + "confirm-delete-multiple-chapters": "Naozaj chcete odstrániť {{count}} kapitolu/zväzky? Nezmení súbory na disku." }, "actionable": { "scan-library": "Skenovať knižnicu", @@ -2239,7 +2240,7 @@ "validation": { "required-field": "Toto pole je povinné", "valid-email": "Toto musí byť platný e-mail", - "password-validation": "Heslo musí mať dĺžku 6 až 32 znakov", + "password-validation": "Heslo musí mať dĺžku 6 až 256 znakov", "year-validation": "Toto musí byť platný rok, dlhší ako 1 000 a 4 znaky" }, "entity-type": { @@ -2276,19 +2277,19 @@ "series-count": "Série {{num}}", "item-count": "{{num}} Položiek", "book-num": "Kniha", - "issue-hash-num": "Problém #", - "issue-num": "Problém", + "issue-hash-num": "Vydanie #", + "issue-num": "Vydanie", "chapter-num": "Kapitola", "volume-num": "Zväzok", "chapter-num-shorthand": "Ch {{num}}", "author-count": "{{num}} Autori", "book-num-shorthand": "Book {{num}}", - "volume-num-shorthand": "Zv. {{num}}", + "volume-num-shorthand": "Zv {{num}}", "issue-num-shorthand": "#{{num}}", "book-nums": "Knihy", "chapter-nums": "Kapitoly", "volume-nums": "Zväzky", - "issue-nums": "Problémy" + "issue-nums": "Vydania" }, "person-detail": { "all-roles": "Roly", diff --git a/UI/Web/src/assets/langs/sv.json b/UI/Web/src/assets/langs/sv.json index 48fa5d5685..935df1c6a7 100644 --- a/UI/Web/src/assets/langs/sv.json +++ b/UI/Web/src/assets/langs/sv.json @@ -2,7 +2,10 @@ "login": { "username": "{{common.username}}", "password": "{{common.password}}", - "password-validation": "{{validation.password-validation}}" + "password-validation": "{{validation.password-validation}}", + "title": "Logga in till ditt konto", + "forgot-password": "Glömt lösenord?", + "submit": "Logga in" }, "edit-user": { "edit": "{{common.edit}}", @@ -11,23 +14,52 @@ "required": "{{validation.required-field}}", "email": "{{common.email}}", "not-valid-email": "{{validation.valid-email}}", - "cancel": "{{common.cancel}}" + "cancel": "{{common.cancel}}", + "account-detail-title": "Kontodetaljer", + "saving": "Sparar…", + "update": "Uppdatera" }, "user-scrobble-history": { "filter-label": "{{common.filter}}", - "special": "{{entity-title.special}}" + "special": "{{entity-title.special}}", + "type-header": "Typ", + "created-header": "Skapad", + "last-modified-header": "Senast ändrad", + "series-header": "Serier", + "volume-and-chapter-num": "Volym {{v}} Kapitel {{n}}", + "no-data": "Ingen data", + "volume-num": "Volym {{num}}", + "chapter-num": "Kapitel {{num}}", + "rating": "Betyg {{r}}", + "not-applicable": "Inte applicerbart", + "processed": "Processad", + "not-processed": "Inte processad", + "description": "Här hittar du all scrobble-aktivitet länkat till ditt konto. För att aktiviteter ska finnas måste du ha en aktiv scrobble-tjänst konfigurerad. All aktivitet som registrerats rensas efter en månad. Om några aktiviteter inte processats kan det bero på att de inte kan matchas. Kontakta din administratör för att få det åtgärdat.", + "data-header": "Data", + "title": "Scrobble-historik", + "not-read-warning": "Leverantör av tjänsten kommer alltid ha högst nummer", + "is-processed-header": "Är processad" }, "review-series-modal": { "close": "{{common.close}}", "save": "{{common.save}}", "delete": "{{common.delete}}", - "required": "{{validation.required-field}}" + "required": "{{validation.required-field}}", + "title": "Redigera recension", + "review-label": "Recension", + "min-length": "Recension måste vara minst {{count}} tecken" }, "review-card-modal": { - "close": "{{common.close}}" + "close": "{{common.close}}", + "external-mod": "(extern)", + "user-review": "{{username}}'s recension", + "go-to-review": "Gå till recension" }, "want-to-read": { - "series-count": "{{common.series-count}}" + "series-count": "{{common.series-count}}", + "title": "Vill läsa", + "no-items": "Det finns inget. Försök lägga till en serie.", + "no-items-filtered": "Ingenting matchar ditt nuvarande filter." }, "user-preferences": { "account-tab": "{{tabs.account-tab}}", @@ -38,7 +70,21 @@ "scrobbling-tab": "{{tabs.scrobbling-tab}}", "smart-filters-tab": "{{tabs.smart-filters-tab}}", "reset": "{{common.reset}}", - "save": "{{common.save}}" + "save": "{{common.save}}", + "prompt-on-download-label": "Fråga vid nedladdning", + "prompt-on-download-tooltip": "Fråga när nedladdning överstiger {{size}}MB i storlek", + "disable-animations-label": "Inaktivera animationer", + "title": "Användarsida", + "pref-description": "Detta är globala inställningar knutet till ditt konto.", + "success-toast": "Användarinställnignar uppdaterade", + "global-settings-title": "Global inställningar", + "page-layout-mode-label": "Sidlayout-läge", + "page-layout-mode-tooltip": "Visa som kort eller listvy på Seriedetaljer-sidan.", + "locale-label": "Plats", + "locale-tooltip": "Språket Kavita ska nyttja", + "blur-unread-summaries-label": "Censurera olästa sammanfattningar", + "blur-unread-summaries-tooltip": "Cencurera sammanfattningar på volymer eller kapitel som inte har någon läsprogress (för att undvika spoilers)", + "disable-animations-tooltip": "Inaktivera animationer på sidan. Användbart på e-ink-läsare." }, "user-holds": { "no-data": "{{typeahead.no-data}}" @@ -668,5 +714,30 @@ }, "actionable": { "clear": "{{common.clear}}" + }, + "dashboard": { + "recently-added-title": "Nyligen tillagda serier", + "more-in-genre-title": "Mer inom {{genre}}", + "server-settings-link": "Serverinställningar", + "no-libraries": "Det är inga bibliotek skapade än. Skapa några i", + "not-granted": "Du har inte fått rättigheter till något bibliotek.", + "on-deck-title": "På hyllan", + "recently-updated-title": "Nyligen uppdaterade serier" + }, + "scrobble-event-type-pipe": { + "want-to-read-remove": "Vill läsa: Ta bort", + "review": "Uppdatera recension", + "chapter-read": "Läsprogress", + "score-updated": "Uppdatera Betyg", + "want-to-read-add": "Vill läsa: Lägg till" + }, + "spoiler": { + "click-to-show": "Spoiler, klicka för att visa" + }, + "review-card": { + "your-review": "Detta är din recension", + "external-review": "Extern recension", + "local-review": "Lokal recension", + "rating-percentage": "Betyg {{r}}%" } } diff --git a/UI/Web/src/assets/langs/zh_Hans.json b/UI/Web/src/assets/langs/zh_Hans.json index 1ea86faf74..f0a6c7c138 100644 --- a/UI/Web/src/assets/langs/zh_Hans.json +++ b/UI/Web/src/assets/langs/zh_Hans.json @@ -453,7 +453,7 @@ "alternative-setting": "另类设定", "alternative-version": "另类版本", "character": "角色", - "contains": "包含", + "contains": "组成", "doujinshi": "同人", "other": "其他", "prequel": "前传", @@ -472,16 +472,16 @@ "ended": "断更" }, "person-role-pipe": { - "artist": "设计师", + "artist": "作画", "character": "角色", - "colorist": "上色师", + "colorist": "上色", "cover-artist": "{{artist}}", "editor": "编辑", - "inker": "上墨师", - "letterer": "嵌字师", + "inker": "墨稿", + "letterer": "嵌字", "penciller": "铅稿", "publisher": "出版社", - "writer": "作家", + "writer": "作者", "other": "其他", "imprint": "压印", "translator": "翻译", @@ -616,7 +616,7 @@ "kavita+-desc-part-1": "Kavita+ 是一项高级订阅服务,可为此 Kavita 实例上的所有用户解锁功能。购买订阅即可解锁 ", "kavita+-desc-part-2": "优质福利", "kavita+-desc-part-3": "今天!", - "kavita+-requirement": "Kavita+ 仅设计为与最新版本(2 个版本)兼容。除此之外的任何版本都可能无法正常工作。", + "kavita+-requirement": "Kavita+ 仅兼容Kavita最新的2个版本。其他任何版本均无法正常使用。", "kavita+-releases": "查看发布", "help-label": "{{common.help}}" }, @@ -856,7 +856,7 @@ "allow-scrobbling-label": "允许Scrobbling", "allow-scrobbling-tooltip": "是否允许Kavita将阅读事件、想读状态、评分和评论记录至已配置的Scrobble服务提供商?本功能仅在激活服务器的Kavita+订阅后才会生效。", "folder-watching-label": "监控文件夹", - "folder-watching-tooltip": "覆盖此资料库服务器的监控文件夹设置。如果关闭此功能,则不会监控此资料库包含的文件夹。如果共享资料库的文件夹,那么文件夹仍可能被监控。每次触发扫描前等待10分钟。", + "folder-watching-tooltip": "覆盖服务器资料库的文件夹监控设置。如果关闭此功能,则不会监控此资料库包含的文件夹。如果共享了资料库的文件夹,那么文件夹仍可能被监控。每次触发扫描前等待10分钟。", "include-in-dashboard-label": "在仪表板中显示", "include-in-dashboard-tooltip": "是否在仪表板上显示此资料库的系列。这会影响所有数据流,例如最近阅读、最近更新、最近添加或其他自定义内容。", "include-in-search-label": "在搜索中显示", @@ -1033,7 +1033,7 @@ "manage-email-settings": { "description": "为了使用 Kavita 的某些功能(例如“发送到设备”),必须设置电子邮件提供商。其他功能(例如“忘记密码”)需要管理员干预,无需设置电子邮件。", "setting-description": "您必须填写主机名和 SMTP 设置才能使用 Kavita 中的基于电子邮件的功能。", - "test-warning": "在點擊“測試”之前,您必須具有有效的設定。", + "test-warning": "在点击“测试”按钮之前,以下设置必须有效。", "send-to-warning": "如果您希望\"发送到设备\"正常工作,您必须设置您的电子邮件设置", "email-url-label": "邮件服务器网址", "email-url-tooltip": "请使用完整的URL地址来配置电子邮件服务,不要包含结尾的斜杠。", @@ -1212,7 +1212,7 @@ "cleanup-tooltip": "Kavita 运行清理任务的频率。这可能很繁重,在大多数情况下应该在午夜执行", "adhoc-tasks-title": "临时任务", "job-title-header": "任务名称", - "description-header": "描述", + "description-header": "人物介绍", "action-header": "操作", "reset-to-default": "{{common.reset-to-default}}", "reset": "{{common.reset}}", @@ -1704,7 +1704,7 @@ "release-year-label": "{{sort-field-pipe.release-year}}", "web-link-description": "您可以在这里添加多个不同的外部网站链接。", "web-link-label": "{{tabs.weblink-tab}}", - "cover-image-description": "选择一张新封面图片并上传。点击保存上传图片并覆盖原有封面。", + "cover-image-description": "选择并上传一张新封面图片。点击保存将上传图片并覆盖原有封面。", "save": "{{common.save}}", "field-locked-alt": "字段已锁定", "info-title": "信息", @@ -2403,7 +2403,7 @@ }, "person-detail": { "all-roles": "角色", - "known-for-title": "众所周知", + "known-for-title": "代表作品", "individual-role-title": "作为 {{role}}", "browse-person-title": "{{name}} 的全部作品", "browse-person-by-role-title": "{{name}} 作为 {{role}} 的所有作品" From 19b0163da79da151f55021a7eb838f90c974081d Mon Sep 17 00:00:00 2001 From: majora2007 Date: Wed, 27 Nov 2024 17:05:01 +0000 Subject: [PATCH 2/4] Bump versions by dotnet-bump-version. --- Kavita.Common/Kavita.Common.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index a0081e81a4..a5e8bb4ff7 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -3,7 +3,7 @@ net8.0 kavitareader.com Kavita - 0.8.4.0 + 0.8.4.1 en true @@ -20,4 +20,4 @@ - + \ No newline at end of file From 85d0d1f0f42e45140ce681fa7627460ed52fed43 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Wed, 27 Nov 2024 13:29:10 -0600 Subject: [PATCH 3/4] v0.8.4.2 - Hotfix (#3422) --- API/Controllers/ChapterController.cs | 28 ++++++++++++++-------------- API/Services/SeriesService.cs | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/API/Controllers/ChapterController.cs b/API/Controllers/ChapterController.cs index 9f2fc4c465..5bd2390865 100644 --- a/API/Controllers/ChapterController.cs +++ b/API/Controllers/ChapterController.cs @@ -92,7 +92,7 @@ public async Task> DeleteChapter(int chapterId) /// Deletes multiple chapters and any volumes with no leftover chapters ///
/// The ID of the series - /// The IDs of the chapters to be deleted + /// The IDs of the chapters to be deleted /// [Authorize(Policy = "RequireAdminRole")] [HttpPost("delete-multiple")] @@ -255,7 +255,7 @@ public async Task UpdateChapterMetadata(UpdateChapterDto dto) // Update writers await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Writers.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Writers.Select(p => p.Name).ToList(), PersonRole.Writer, _unitOfWork ); @@ -263,7 +263,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update characters await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Characters.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Characters.Select(p => p.Name).ToList(), PersonRole.Character, _unitOfWork ); @@ -271,7 +271,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update pencillers await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Pencillers.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Pencillers.Select(p => p.Name).ToList(), PersonRole.Penciller, _unitOfWork ); @@ -279,7 +279,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update inkers await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Inkers.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Inkers.Select(p => p.Name).ToList(), PersonRole.Inker, _unitOfWork ); @@ -287,7 +287,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update colorists await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Colorists.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Colorists.Select(p => p.Name).ToList(), PersonRole.Colorist, _unitOfWork ); @@ -295,7 +295,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update letterers await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Letterers.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Letterers.Select(p => p.Name).ToList(), PersonRole.Letterer, _unitOfWork ); @@ -303,7 +303,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update cover artists await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.CoverArtists.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.CoverArtists.Select(p => p.Name).ToList(), PersonRole.CoverArtist, _unitOfWork ); @@ -311,7 +311,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update editors await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Editors.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Editors.Select(p => p.Name).ToList(), PersonRole.Editor, _unitOfWork ); @@ -319,7 +319,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update publishers await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Publishers.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Publishers.Select(p => p.Name).ToList(), PersonRole.Publisher, _unitOfWork ); @@ -327,7 +327,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update translators await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Translators.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Translators.Select(p => p.Name).ToList(), PersonRole.Translator, _unitOfWork ); @@ -335,7 +335,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update imprints await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Imprints.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Imprints.Select(p => p.Name).ToList(), PersonRole.Imprint, _unitOfWork ); @@ -343,7 +343,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update teams await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Teams.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Teams.Select(p => p.Name).ToList(), PersonRole.Team, _unitOfWork ); @@ -351,7 +351,7 @@ await PersonHelper.UpdateChapterPeopleAsync( // Update locations await PersonHelper.UpdateChapterPeopleAsync( chapter, - dto.Locations.Select(p => Parser.Normalize(p.Name)).ToList(), + dto.Locations.Select(p => p.Name).ToList(), PersonRole.Location, _unitOfWork ); diff --git a/API/Services/SeriesService.cs b/API/Services/SeriesService.cs index 119baaf941..7d4a4b95ad 100644 --- a/API/Services/SeriesService.cs +++ b/API/Services/SeriesService.cs @@ -343,7 +343,7 @@ private async Task HandlePeopleUpdateAsync(SeriesMetadata metadata, ICollection< var existingPeople = await _unitOfWork.PersonRepository.GetPeopleByNames(normalizedNames); // Use a dictionary for quick lookups - var existingPeopleDictionary = existingPeople.ToDictionary(p => p.NormalizedName, p => p); + var existingPeopleDictionary = existingPeople.DistinctBy(p => p.NormalizedName).ToDictionary(p => p.NormalizedName, p => p); // List to track people that will be added to the metadata var peopleToAdd = new List(); From fc7c49f5ccbbd9113f6dfee17882aa640eca52b7 Mon Sep 17 00:00:00 2001 From: majora2007 Date: Wed, 27 Nov 2024 19:29:51 +0000 Subject: [PATCH 4/4] Bump versions by dotnet-bump-version. --- Kavita.Common/Kavita.Common.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index a5e8bb4ff7..ea45979329 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -3,7 +3,7 @@ net8.0 kavitareader.com Kavita - 0.8.4.1 + 0.8.4.2 en true