From 09317263538244fac675a3d593e05a146fae3cf4 Mon Sep 17 00:00:00 2001 From: Stefan Blixten Karlsson Date: Wed, 25 Mar 2026 17:33:11 +0100 Subject: [PATCH 01/11] fix: swedish translation (#1476) ## Summary * **What is the goal of this PR?** fix swedish translation * **What changes are included?** lib\I18n\translations\swedish.yaml ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ --- lib/I18n/translations/swedish.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/I18n/translations/swedish.yaml b/lib/I18n/translations/swedish.yaml index 3d6e76f0..c5e577e3 100644 --- a/lib/I18n/translations/swedish.yaml +++ b/lib/I18n/translations/swedish.yaml @@ -78,9 +78,10 @@ STR_FONT_FAMILY: "Eboksläsarens typsnittsfamilj" STR_FONT_SIZE: "Eboksläsarens typsnittsstorlek" STR_LINE_SPACING: "Eboksläsarens linjemellanrum" STR_SCREEN_MARGIN: "Eboksläsarens skärmmarginal" -STR_PARA_ALIGNMENT: "Eboksläsarens paragraflinjeplacering" +STR_PARA_ALIGNMENT: "Eboksläsarens paragrafjustering" STR_HYPHENATION: "Avstavning" STR_TIME_TO_SLEEP: "Tid för att gå i vila" +STR_SHOW_HIDDEN_FILES: "Visa dolda filer" STR_REFRESH_FREQ: "Uppdateringsfrekvens" STR_KOREADER_SYNC: "KOReader-synkronisering" STR_CHECK_UPDATES: "Kolla efter uppdateringar" @@ -142,7 +143,7 @@ STR_X_LARGE: "Extra stor" STR_TIGHT: "Smal" STR_NORMAL: "Normal" STR_WIDE: "Bred" -STR_JUSTIFY: "Rättfärdiga" +STR_JUSTIFY: "Justerad" STR_ALIGN_LEFT: "Vänster" STR_CENTER: "Mitten" STR_ALIGN_RIGHT: "Höger" @@ -224,7 +225,7 @@ STR_BATTERY: "Batteri" STR_UI_THEME: "Användargränssnittstema" STR_THEME_CLASSIC: "Klassisk" STR_THEME_LYRA: "Lyra" -STR_THEME_LYRA_EXTENDED: "Lyra Extended" +STR_THEME_LYRA_EXTENDED: "Lyra utökad" STR_SUNLIGHT_FADING_FIX: "Fix för solskensmattning" STR_REMAP_FRONT_BUTTONS: "Ändra frontknappar" STR_OPDS_BROWSER: "OPDS-webbläsare" From 59714b4fd610ef78afff61eb8372e09560a4bfd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80ngel?= <153315454+angeldenom@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:34:17 +0100 Subject: [PATCH 02/11] chore: Catalan localization for STR_SHOW_HIDDEN_FILES (#1494) ## Summary * **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.) Adds the missing Catalan translation for STR_SHOW_HIDDEN_FILES in lib/I18n/translations/catalan.yaml. * **What changes are included?** Only modified catalan.yaml file ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? NO --- lib/I18n/translations/catalan.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/I18n/translations/catalan.yaml b/lib/I18n/translations/catalan.yaml index 29130ac9..a585019f 100644 --- a/lib/I18n/translations/catalan.yaml +++ b/lib/I18n/translations/catalan.yaml @@ -81,6 +81,7 @@ STR_SCREEN_MARGIN: "Marge de pantalla del lector" STR_PARA_ALIGNMENT: "Alineació de paràgrafs del lector" STR_HYPHENATION: "Partició de mots" STR_TIME_TO_SLEEP: "Temps per entrar en repòs" +STR_SHOW_HIDDEN_FILES: "Mostra fitxers ocults" STR_REFRESH_FREQ: "Freqüència de refresc" STR_KOREADER_SYNC: "Sincronització del KOReader" STR_CHECK_UPDATES: "Comprova si hi ha actualitzacions" From de2b66161805dd4fcfb844b355bf966bdfbe8091 Mon Sep 17 00:00:00 2001 From: Jonasz Potoniec Date: Wed, 25 Mar 2026 17:34:40 +0100 Subject: [PATCH 03/11] chore: Polish localization for STR_SHOW_HIDDEN_FILES (#1490) ## Summary Polish localization for `STR_SHOW_HIDDEN_FILES` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ --- lib/I18n/translations/polish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/I18n/translations/polish.yaml b/lib/I18n/translations/polish.yaml index d669ec27..c5d9fed1 100644 --- a/lib/I18n/translations/polish.yaml +++ b/lib/I18n/translations/polish.yaml @@ -81,6 +81,7 @@ STR_SCREEN_MARGIN: "Marginesy ekranu" STR_PARA_ALIGNMENT: "Wyjustowanie paragrafów" STR_HYPHENATION: "Dzielenie wyrazów" STR_TIME_TO_SLEEP: "Czas do uśpienia" +STR_SHOW_HIDDEN_FILES: "Pokaż ukryte pliki" STR_REFRESH_FREQ: "Częstotliwość odświeżania" STR_KOREADER_SYNC: "KOReader Sync" STR_CHECK_UPDATES: "Sprawdź uaktualnia" From 72b00e9e3f6f275f1bf51a0b98bedd54fca514f8 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Wed, 25 Mar 2026 17:34:53 +0100 Subject: [PATCH 04/11] chore: Update German translation strings (#1495) ## Summary * **What is the goal of this PR?** Updating German language file * **What changes are included?** ## Additional Context - None --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< NO >**_ --- lib/I18n/translations/german.yaml | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/I18n/translations/german.yaml b/lib/I18n/translations/german.yaml index 0aac033c..b53ff494 100644 --- a/lib/I18n/translations/german.yaml +++ b/lib/I18n/translations/german.yaml @@ -98,6 +98,11 @@ STR_AUTH_SUCCESS: "Erfolgreich authentifiziert!" STR_KOREADER_AUTH: "KOReader-Auth" STR_SYNC_READY: "KOReader-Synchronisierung bereit" STR_AUTH_FAILED: "Authentifizierung fehlg." +STR_REGISTER: "Registrieren" +STR_REGISTERING: "Registrierung..." +STR_REGISTER_SUCCESS: "Konto erfolgreich erstellt!" +STR_REGISTER_FAILED: "Registrierung fehlgeschlagen" +STR_USERNAME_TAKEN: "Benutzername bereits vergeben" STR_DONE: "Erledigt" STR_CLEAR_CACHE_WARNING_1: "Alle Buch-Caches werden geleert." STR_CLEAR_CACHE_WARNING_2: "Lesefortschritt wird gelöscht!" @@ -250,6 +255,7 @@ STR_SYNC_PROGRESS: "Fortschritt synchronisieren" STR_DELETE_CACHE: "Buch-Cache leeren" STR_DISPLAY_QR: "Seite als QR anzeigen" STR_DELETE: "Löschen" +STR_REMOVE: "Entfernen" STR_CHAPTER_PREFIX: "Kapitel:" STR_PAGES_SEPARATOR: " Seiten | " STR_BOOK_PREFIX: "Buch: " @@ -285,3 +291,32 @@ STR_NO_FOOTNOTES: "Keine Fußnoten auf dieser Seite" STR_LINK: "[Link]" STR_AUTO_TURN_ENABLED: "Auto-Umblättern aktiv: " STR_AUTO_TURN_PAGES_PER_MIN: "Auto-Umblättern (Seiten/Min.)" +STR_IMAGES: "Bilder" +STR_IMAGES_DISPLAY: "Darstellung" +STR_IMAGES_PLACEHOLDER: "Platzhalter" +STR_IMAGES_SUPPRESS: "Unterdrücken" +STR_SHOW_HIDDEN_FILES: "Versteckte Dateien anzeigen" +STR_PAGE_OVERLAY: "Seiten-Overlay" +STR_RECENTS: "Zuletzt" +STR_MAPPING_REMOTE: "Externe Position zuordnen..." +STR_MAPPING_LOCAL: "Lokale Position berechnen..." +STR_INFO: "Info" +STR_AUTHOR: "Autor" +STR_SERIES: "Reihe" +STR_FILE_SIZE: "Größe" +STR_SLEEP_COVER_OVERLAY: "Standby-Info-Overlay" +STR_SYSTEM_INFO: "Systeminformationen" +STR_LOAD_XTC_FAILED: "XTC-Datei konnte nicht geladen werden" +STR_LOAD_EPUB_FAILED: "EPUB-Datei konnte nicht geladen werden" +STR_FW_VERSION: "FW-Version" +STR_CHIP: "Chip" +STR_CPU: "CPU" +STR_MHZ: "MHz" +STR_FREE_RAM: "Freier RAM" +STR_MIN_FREE: "Min. frei" +STR_MAX_BLOCK: "Max. Block" +STR_FLASH_USED: "Flash belegt" +STR_UPTIME: "Laufzeit" +STR_CHARGING: "Lädt" +STR_GATHERING_DATA: "Daten werden gesammelt..." +STR_READING: "Lese..." From 603aead5d9a765423b500027ce89bcd4844c87ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B3=D0=BE=D1=80=20=D0=9C=D0=B0=D1=80=D1=82=D1=8B?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Mar 2026 23:35:10 +0700 Subject: [PATCH 05/11] feat: update Russian translation (#1489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Adds new Russian strings for recently merged features, yay! 😃 --- ### AI Usage Did you use AI tools to help write this code? _**NO**_ --- lib/I18n/translations/russian.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/I18n/translations/russian.yaml b/lib/I18n/translations/russian.yaml index 0cda986e..82a1c188 100644 --- a/lib/I18n/translations/russian.yaml +++ b/lib/I18n/translations/russian.yaml @@ -66,6 +66,10 @@ STR_SLEEP_COVER_MODE: "Режим обложки сна" STR_HIDE_BATTERY: "Скрыть % батареи" STR_EXTRA_SPACING: "Доп. интервал абзаца" STR_TEXT_AA: "Сглаживание текста" +STR_IMAGES: "Изображения" +STR_IMAGES_DISPLAY: "Показать" +STR_IMAGES_PLACEHOLDER: "Заглушки" +STR_IMAGES_SUPPRESS: "Скрыть" STR_SHORT_PWR_BTN: "Короткое нажатие PWR" STR_ORIENTATION: "Ориентация чтения" STR_SIDE_BTN_LAYOUT: "Боковые кнопки" @@ -77,6 +81,7 @@ STR_SCREEN_MARGIN: "Поля экрана" STR_PARA_ALIGNMENT: "Выравнивание абзаца" STR_HYPHENATION: "Перенос слов" STR_TIME_TO_SLEEP: "Сон через" +STR_SHOW_HIDDEN_FILES: "Показать скрытые файлы" STR_REFRESH_FREQ: "Частота обновления" STR_KOREADER_SYNC: "Синхронизация KOReader" STR_CHECK_UPDATES: "Проверить обновления" @@ -212,6 +217,7 @@ STR_PROGRESS_BAR_MEDIUM: "Средний" STR_PROGRESS_BAR_THICK: "Толстый" STR_BOOK: "Книга" STR_CHAPTER: "Глава" +STR_EXAMPLE_CHAPTER: "Глава 21" STR_EXAMPLE_BOOK: "Название книги" STR_PREVIEW: "Предпросмотр" STR_TITLE: "Заглавие" @@ -223,6 +229,9 @@ STR_THEME_LYRA_EXTENDED: "Lyra Extended" STR_SUNLIGHT_FADING_FIX: "Компенсация выцветания" STR_REMAP_FRONT_BUTTONS: "Переназначить передние кнопки" STR_OPDS_BROWSER: "OPDS браузер" +STR_FOOTNOTES: "Примечания" +STR_NO_FOOTNOTES: "На данной странице нет примечаний" +STR_LINK: "[ссылка]" STR_COVER_CUSTOM: "Обложка + Свой" STR_MENU_RECENT_BOOKS: "Недавние книги" STR_NO_RECENT_BOOKS: "Нет недавних книг" @@ -279,3 +288,5 @@ STR_BOOK_S_STYLE: "Стиль книги" STR_EMBEDDED_STYLE: "Встроенный стиль" STR_OPDS_SERVER_URL: "URL OPDS сервера" STR_SCREENSHOT_BUTTON: "Сделать снимок экрана" +STR_AUTO_TURN_ENABLED: "Авто-поворот включён: " +STR_AUTO_TURN_PAGES_PER_MIN: "Авто-поворот (Страниц в минуту)" From f803bd03714982fc9bf434bc457a67feb39242f8 Mon Sep 17 00:00:00 2001 From: Mirus Date: Thu, 26 Mar 2026 03:59:18 +0200 Subject: [PATCH 06/11] feat: Add Ukrainian translations for image-related strings (#1491) ## Summary Prep for RC 1.2.0 https://github.com/crosspoint-reader/crosspoint-reader/pull/1483 --- lib/I18n/translations/ukrainian.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/I18n/translations/ukrainian.yaml b/lib/I18n/translations/ukrainian.yaml index 16b69760..9eefa022 100644 --- a/lib/I18n/translations/ukrainian.yaml +++ b/lib/I18n/translations/ukrainian.yaml @@ -66,6 +66,10 @@ STR_SLEEP_COVER_MODE: "Режим обкладинки екрана сну" STR_HIDE_BATTERY: "Приховати % батареї" STR_EXTRA_SPACING: "Додатковий інтервал між абзацами" STR_TEXT_AA: "Згладжування тексту" +STR_IMAGES: "Зображення" +STR_IMAGES_DISPLAY: "Показати" +STR_IMAGES_PLACEHOLDER: "Заглушка" +STR_IMAGES_SUPPRESS: "Приховати" STR_SHORT_PWR_BTN: "Коротке натискання кнопки живлення" STR_ORIENTATION: "Орієнтація читання" STR_SIDE_BTN_LAYOUT: "Розташування бічних кнопок (читач)" @@ -81,6 +85,7 @@ STR_REFRESH_FREQ: "Частота оновлення" STR_KOREADER_SYNC: "Синхронізація KOReader" STR_CHECK_UPDATES: "Перевірити оновлення" STR_LANGUAGE: "Мова" +STR_SHOW_HIDDEN_FILES: "Показати приховані файли" STR_CLEAR_READING_CACHE: "Очистити кеш читання" STR_USERNAME: "Ім'я користувача" STR_PASSWORD: "Пароль" From 3f9c43506ba7127316b2bfb93db9ae3d7f3ee416 Mon Sep 17 00:00:00 2001 From: Spigaw <73850535+Spigaw@users.noreply.github.com> Date: Thu, 26 Mar 2026 03:03:24 +0100 Subject: [PATCH 07/11] chore: Add missing French translations for UI controls and settings (#1493) Added missing strings for the French translation. ## Summary Adding the missing French translated strings before the next PR. No modification done to the preexisting strings, only added new ones. ## Additional Context N/A --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. No AI usage. --- lib/I18n/translations/french.yaml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/I18n/translations/french.yaml b/lib/I18n/translations/french.yaml index cecf85d2..f91e46f4 100644 --- a/lib/I18n/translations/french.yaml +++ b/lib/I18n/translations/french.yaml @@ -66,6 +66,10 @@ STR_SLEEP_COVER_MODE: "Mode écran de veille" STR_HIDE_BATTERY: "Masquer % batterie" STR_EXTRA_SPACING: "Espacement paragraphes" STR_TEXT_AA: "Lissage du texte" +STR_IMAGES: "Images" +STR_IMAGES_DISPLAY: "Affichage" +STR_IMAGES_PLACEHOLDER: "Espace réservé" +STR_IMAGES_SUPPRESS: "Masquer" STR_SHORT_PWR_BTN: "Appui court alim." STR_ORIENTATION: "Orientation de lecture" STR_SIDE_BTN_LAYOUT: "Boutons latéraux" @@ -77,6 +81,7 @@ STR_SCREEN_MARGIN: "Marges du lecteur" STR_PARA_ALIGNMENT: "Alignement du texte" STR_HYPHENATION: "Césure" STR_TIME_TO_SLEEP: "Mise en veille auto" +STR_SHOW_HIDDEN_FILES: "Afficher les fichiers cachés" STR_REFRESH_FREQ: "Fréquence rafraîchissement" STR_KOREADER_SYNC: "Synchro KOReader" STR_CHECK_UPDATES: "Mise à jour" @@ -180,6 +185,7 @@ STR_BACK: "« Retour" STR_EXIT: "« Quitter" STR_HOME: "« Accueil" STR_SELECT: "OK" +STR_SELECTED: "Sélectionné" STR_TOGGLE: "Modifier" STR_CONFIRM: "Confirmer" STR_CANCEL: "Annuler" @@ -189,6 +195,8 @@ STR_DOWNLOAD: "Télécharger" STR_RETRY: "Réessayer" STR_YES: "Oui" STR_NO: "Non" +STR_SHOW: "Afficher" +STR_HIDE: "Masquer" STR_STATE_ON: "ON" STR_STATE_OFF: "OFF" STR_NOT_SET: "Non défini" @@ -199,6 +207,21 @@ STR_DIR_DOWN: "Bas" STR_OK_BUTTON: "OK" STR_SLEEP_COVER_FILTER: "Filtre écran de veille" STR_FILTER_CONTRAST: "Contraste" +STR_CUSTOMISE_STATUS_BAR: "Personnaliser la barre d'état" +STR_CHAPTER_PAGE_COUNT: "Nombre de pages du chapitre" +STR_BOOK_PROGRESS_PERCENTAGE: "Pourcentage de progression" +STR_PROGRESS_BAR: "Barre de progression" +STR_PROGRESS_BAR_THICKNESS: "Épaisseur de la barre" +STR_PROGRESS_BAR_THIN: "Fine" +STR_PROGRESS_BAR_MEDIUM: "Moyenne" +STR_PROGRESS_BAR_THICK: "Épaisse" +STR_BOOK: "Livre" +STR_CHAPTER: "Chapitre" +STR_EXAMPLE_CHAPTER: "Chapitre 21" +STR_EXAMPLE_BOOK: "Titre du livre" +STR_PREVIEW: "Aperçu" +STR_TITLE: "Titre" +STR_BATTERY: "Batterie" STR_UI_THEME: "Thème interface" STR_THEME_CLASSIC: "Classique" STR_THEME_LYRA: "Lyra" @@ -231,6 +254,7 @@ STR_GO_HOME_BUTTON: "Retour Accueil" STR_SYNC_PROGRESS: "Synchro progression" STR_DELETE_CACHE: "Supprimer cache livre" STR_DELETE: "Supprimer" +STR_DISPLAY_QR: "Afficher la page en QR" STR_CHAPTER_PREFIX: "Chapitre : " STR_PAGES_SEPARATOR: " pages | " STR_BOOK_PREFIX: "Livre : " @@ -260,4 +284,9 @@ STR_UPLOAD: "Envoyer" STR_BOOK_S_STYLE: "Style du livre" STR_EMBEDDED_STYLE: "Style intégré" STR_OPDS_SERVER_URL: "URL serveur OPDS" +STR_FOOTNOTES: "Notes de bas de page" +STR_NO_FOOTNOTES: "Aucune note sur cette page" +STR_LINK: "[lien]" STR_SCREENSHOT_BUTTON: "Capture d'écran" +STR_AUTO_TURN_ENABLED: "Tourne-page auto : " +STR_AUTO_TURN_PAGES_PER_MIN: "Tourne-page auto (pages par minute)" From 5b43639f984014ed349d1f417f48013c1e892351 Mon Sep 17 00:00:00 2001 From: ariel-lindemann <41641978+ariel-lindemann@users.noreply.github.com> Date: Thu, 26 Mar 2026 07:49:20 +0100 Subject: [PATCH 08/11] chore: update RO translation for release v1.2.0 (#1504) --- lib/I18n/translations/romanian.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/I18n/translations/romanian.yaml b/lib/I18n/translations/romanian.yaml index 64631807..27ec6e4a 100644 --- a/lib/I18n/translations/romanian.yaml +++ b/lib/I18n/translations/romanian.yaml @@ -12,7 +12,7 @@ STR_SETTINGS_TITLE: "Setări" STR_CONTINUE_READING: "Continuă lectura" STR_NO_OPEN_BOOK: "Nicio carte deschisă" STR_START_READING: "Începeţi lectura" -STR_NO_FILES_FOUND: "Nu s-au găsit fișiere" +STR_NO_FILES_FOUND: "Nu s-au găsit fişiere" STR_SELECT_CHAPTER: "Selectaţi capitolul" STR_NO_CHAPTERS: "Niciun capitol" STR_END_OF_BOOK: "Sfârşitul cărţii" @@ -66,6 +66,10 @@ STR_SLEEP_COVER_MODE: "Mod ecran de repaus cu copertă" STR_HIDE_BATTERY: "Ascunde procentul bateriei" STR_EXTRA_SPACING: "Spaţiere suplimentară între paragrafe" STR_TEXT_AA: "Anti-Aliasing text" +STR_IMAGES: "Imagini" +STR_IMAGES_DISPLAY: "Afişare" +STR_IMAGES_PLACEHOLDER: "Substituent" +STR_IMAGES_SUPPRESS: "Suprimare" STR_SHORT_PWR_BTN: "Apăsare scurtă întrerupător" STR_ORIENTATION: "Orientare lectură" STR_SIDE_BTN_LAYOUT: "Aspect butoane laterale (lectură)" @@ -77,6 +81,7 @@ STR_SCREEN_MARGIN: "Margine ecran lectură" STR_PARA_ALIGNMENT: "Aliniere paragrafe reader" STR_HYPHENATION: "Silabisire" STR_TIME_TO_SLEEP: "Timp până la repaus" +STR_SHOW_HIDDEN_FILES: "Afişează fişierele ascunse" STR_REFRESH_FREQ: "Frecvenţă reîmprospătare" STR_KOREADER_SYNC: "Sincronizare KOReader" STR_CHECK_UPDATES: "Căutaţi actualizări" @@ -190,7 +195,7 @@ STR_DOWNLOAD: "Descarcă" STR_RETRY: "Reîncercare" STR_YES: "Da" STR_NO: "Nu" -STR_SHOW: "Afișează" +STR_SHOW: "Afişează" STR_HIDE: "Ascunde" STR_STATE_ON: "Pornit" STR_STATE_OFF: "Oprit" @@ -249,7 +254,7 @@ STR_GO_HOME_BUTTON: "Acasă" STR_SYNC_PROGRESS: "Progres sincronizare" STR_DELETE_CACHE: "Ştergere cache cărţi" STR_DELETE: "Ştergeți" -STR_DISPLAY_QR: "Afișați pagina ca cod QR" +STR_DISPLAY_QR: "Afişați pagina ca cod QR" STR_CHAPTER_PREFIX: "Capitol: " STR_PAGES_SEPARATOR: " pagini | " STR_BOOK_PREFIX: "Carte: " From 3f8a87e9076619ed25d108092257320ce97f87bd Mon Sep 17 00:00:00 2001 From: jpirnay Date: Fri, 27 Mar 2026 16:40:34 +0100 Subject: [PATCH 09/11] Deal with invalid/incomplete toc.ncx files --- lib/Epub/Epub.cpp | 88 +++++++++++++++++++++++++++++- lib/Epub/Epub.h | 3 + lib/I18n/translations/english.yaml | 1 + src/CrossPointSettings.h | 2 + src/SettingsList.h | 2 + 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index cb0b1801..68255df4 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -7,11 +7,13 @@ #include #include +#include "CrossPointSettings.h" #include "Epub/parsers/ContainerParser.h" #include "Epub/parsers/ContentOpfParser.h" #include "Epub/parsers/TocNavParser.h" #include "Epub/parsers/TocNcxParser.h" + bool Epub::findContentOpfFile(std::string* contentOpfFile) const { const auto containerPath = "META-INF/container.xml"; size_t containerSize; @@ -333,6 +335,7 @@ void Epub::parseCssFiles() const { // load in the meta data for the epub file bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) { LOG_DBG("EBP", "Loading ePub: %s", filepath.c_str()); + tocReliabilityState = -1; // Initialize spine/TOC cache bookMetadataCache.reset(new BookMetadataCache(cachePath)); @@ -767,6 +770,18 @@ BookMetadataCache::TocEntry Epub::getTocItem(const int tocIndex) const { return {}; } + if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + const int spineCount = bookMetadataCache->getSpineCount(); + if (tocIndex < 0 || tocIndex >= spineCount) { + LOG_DBG("EBP", "getTocItem synthetic index:%d is out of range", tocIndex); + return {}; + } + + const auto spine = bookMetadataCache->getSpineEntry(tocIndex); + return BookMetadataCache::TocEntry("Section " + std::to_string(tocIndex + 1), spine.href, "", 1, + static_cast(tocIndex)); + } + if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) { LOG_DBG("EBP", "getTocItem index:%d is out of range", tocIndex); return {}; @@ -780,6 +795,10 @@ int Epub::getTocItemsCount() const { return 0; } + if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + return bookMetadataCache->getSpineCount(); + } + return bookMetadataCache->getTocCount(); } @@ -790,6 +809,14 @@ int Epub::getSpineIndexForTocIndex(const int tocIndex) const { return 0; } + if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + if (tocIndex < 0 || tocIndex >= bookMetadataCache->getSpineCount()) { + LOG_ERR("EBP", "getSpineIndexForTocIndex synthetic tocIndex %d out of range", tocIndex); + return 0; + } + return tocIndex; + } + if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) { LOG_ERR("EBP", "getSpineIndexForTocIndex: tocIndex %d out of range", tocIndex); return 0; @@ -804,7 +831,66 @@ int Epub::getSpineIndexForTocIndex(const int tocIndex) const { return spineIndex; } -int Epub::getTocIndexForSpineIndex(const int spineIndex) const { return getSpineItem(spineIndex).tocIndex; } +bool Epub::hasReliableToc() const { + if (tocReliabilityState != -1) { + return tocReliabilityState == 1; + } + + if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { + tocReliabilityState = 0; + return false; + } + + const int spineCount = bookMetadataCache->getSpineCount(); + const int tocCount = bookMetadataCache->getTocCount(); + + if (spineCount <= 0 || tocCount <= 0) { + tocReliabilityState = 0; + return false; + } + + // If a larger book only exposes one TOC entry, treat TOC as unusable for chapter UX. + if (spineCount >= 8 && tocCount <= 1) { + tocReliabilityState = 0; + return false; + } + + std::vector spineReferenced(static_cast(spineCount), false); + int distinctSpinesReferenced = 0; + for (int i = 0; i < tocCount; i++) { + const auto toc = bookMetadataCache->getTocEntry(i); + if (toc.spineIndex >= 0 && toc.spineIndex < spineCount) { + const size_t idx = static_cast(toc.spineIndex); + if (!spineReferenced[idx]) { + spineReferenced[idx] = true; + distinctSpinesReferenced++; + } + } + } + + // Require at least 25% spine coverage from TOC references. + const bool reliable = (distinctSpinesReferenced * 4 >= spineCount); + tocReliabilityState = reliable ? 1 : 0; + return reliable; +} + +int Epub::getTocIndexForSpineIndex(const int spineIndex) const { + if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { + LOG_ERR("EBP", "getTocIndexForSpineIndex called but cache not loaded"); + return 0; + } + + if (spineIndex < 0 || spineIndex >= bookMetadataCache->getSpineCount()) { + LOG_ERR("EBP", "getTocIndexForSpineIndex: spineIndex %d out of range", spineIndex); + return 0; + } + + if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + return spineIndex; + } + + return bookMetadataCache->getSpineEntry(spineIndex).tocIndex; +} size_t Epub::getBookSize() const { if (!bookMetadataCache || !bookMetadataCache->isLoaded() || bookMetadataCache->getSpineCount() == 0) { diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index 9ffa8d37..943eaeb5 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -29,6 +29,8 @@ class Epub { std::unique_ptr cssParser; // CSS files std::vector cssFiles; + // -1 unknown, 0 unreliable, 1 reliable + mutable int tocReliabilityState = -1; bool findContentOpfFile(std::string* contentOpfFile) const; bool parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata); @@ -66,6 +68,7 @@ class Epub { int getTocItemsCount() const; int getSpineIndexForTocIndex(int tocIndex) const; int getTocIndexForSpineIndex(int spineIndex) const; + bool hasReliableToc() const; size_t getCumulativeSpineItemSize(int spineIndex) const; int getSpineIndexForTextReference() const; diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index df91c1a1..3204b62e 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -70,6 +70,7 @@ STR_IMAGES: "Images" STR_IMAGES_DISPLAY: "Display" STR_IMAGES_PLACEHOLDER: "Placeholder" STR_IMAGES_SUPPRESS: "Suppress" +STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Create fallback for invalid TOC" STR_SHORT_PWR_BTN: "Short Power Button Click" STR_ORIENTATION: "Reading Orientation" STR_SIDE_BTN_LAYOUT: "Side Button Layout (reader)" diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index 9a0e298b..c3881589 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -199,6 +199,8 @@ class CrossPointSettings { uint8_t showHiddenFiles = 0; // Image rendering mode in EPUB reader uint8_t imageRendering = IMAGES_DISPLAY; + // Enable synthetic TOC fallback for malformed/sparse TOC books (1 = enabled, 0 = disabled) + uint8_t syntheticTocFallback = 1; ~CrossPointSettings() = default; diff --git a/src/SettingsList.h b/src/SettingsList.h index cdbee372..5c21bf23 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -65,6 +65,8 @@ inline const std::vector& getSettingsList() { SettingInfo::Enum(StrId::STR_IMAGES, &CrossPointSettings::imageRendering, {StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS}, "imageRendering", StrId::STR_CAT_READER), + SettingInfo::Toggle(StrId::STR_CREATE_FALLBACK_FOR_INVALID_TOC, &CrossPointSettings::syntheticTocFallback, + "syntheticTocFallback", StrId::STR_CAT_READER), // --- Controls --- SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout, {StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS), From a51fd3953de52ba20219be784d2d4aa6b4f29f16 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Fri, 27 Mar 2026 17:06:30 +0100 Subject: [PATCH 10/11] Refactor to a more generic unobstrusive approach --- lib/Epub/Epub.cpp | 10 ++++------ lib/Epub/Epub.h | 3 +++ src/activities/reader/ReaderActivity.cpp | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 68255df4..7c1120f9 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -7,13 +7,11 @@ #include #include -#include "CrossPointSettings.h" #include "Epub/parsers/ContainerParser.h" #include "Epub/parsers/ContentOpfParser.h" #include "Epub/parsers/TocNavParser.h" #include "Epub/parsers/TocNcxParser.h" - bool Epub::findContentOpfFile(std::string* contentOpfFile) const { const auto containerPath = "META-INF/container.xml"; size_t containerSize; @@ -770,7 +768,7 @@ BookMetadataCache::TocEntry Epub::getTocItem(const int tocIndex) const { return {}; } - if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + if (syntheticTocFallbackEnabled && !hasReliableToc()) { const int spineCount = bookMetadataCache->getSpineCount(); if (tocIndex < 0 || tocIndex >= spineCount) { LOG_DBG("EBP", "getTocItem synthetic index:%d is out of range", tocIndex); @@ -795,7 +793,7 @@ int Epub::getTocItemsCount() const { return 0; } - if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + if (syntheticTocFallbackEnabled && !hasReliableToc()) { return bookMetadataCache->getSpineCount(); } @@ -809,7 +807,7 @@ int Epub::getSpineIndexForTocIndex(const int tocIndex) const { return 0; } - if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + if (syntheticTocFallbackEnabled && !hasReliableToc()) { if (tocIndex < 0 || tocIndex >= bookMetadataCache->getSpineCount()) { LOG_ERR("EBP", "getSpineIndexForTocIndex synthetic tocIndex %d out of range", tocIndex); return 0; @@ -885,7 +883,7 @@ int Epub::getTocIndexForSpineIndex(const int spineIndex) const { return 0; } - if (SETTINGS.syntheticTocFallback && !hasReliableToc()) { + if (syntheticTocFallbackEnabled && !hasReliableToc()) { return spineIndex; } diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index 943eaeb5..7ea0034a 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -31,6 +31,8 @@ class Epub { std::vector cssFiles; // -1 unknown, 0 unreliable, 1 reliable mutable int tocReliabilityState = -1; + // Library-level option: app code can override this per-book instance. + bool syntheticTocFallbackEnabled = false; bool findContentOpfFile(std::string* contentOpfFile) const; bool parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata); @@ -69,6 +71,7 @@ class Epub { int getSpineIndexForTocIndex(int tocIndex) const; int getTocIndexForSpineIndex(int spineIndex) const; bool hasReliableToc() const; + void setSyntheticTocFallbackEnabled(bool enabled) { syntheticTocFallbackEnabled = enabled; } size_t getCumulativeSpineItemSize(int spineIndex) const; int getSpineIndexForTextReference() const; diff --git a/src/activities/reader/ReaderActivity.cpp b/src/activities/reader/ReaderActivity.cpp index 2164a7f6..6a62cb70 100644 --- a/src/activities/reader/ReaderActivity.cpp +++ b/src/activities/reader/ReaderActivity.cpp @@ -37,6 +37,7 @@ std::unique_ptr ReaderActivity::loadEpub(const std::string& path) { } auto epub = std::unique_ptr(new Epub(path, "/.crosspoint")); + epub->setSyntheticTocFallbackEnabled(SETTINGS.syntheticTocFallback != 0); if (epub->load(true, SETTINGS.embeddedStyle == 0)) { return epub; } From 20d5cf96f77f71d8c18ebc62755620fe90abfb78 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Fri, 27 Mar 2026 17:28:06 +0100 Subject: [PATCH 11/11] Proper return code --- lib/Epub/Epub.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 7c1120f9..119743e2 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -875,12 +875,12 @@ bool Epub::hasReliableToc() const { int Epub::getTocIndexForSpineIndex(const int spineIndex) const { if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { LOG_ERR("EBP", "getTocIndexForSpineIndex called but cache not loaded"); - return 0; + return -1; } if (spineIndex < 0 || spineIndex >= bookMetadataCache->getSpineCount()) { LOG_ERR("EBP", "getTocIndexForSpineIndex: spineIndex %d out of range", spineIndex); - return 0; + return -1; } if (syntheticTocFallbackEnabled && !hasReliableToc()) {