## Summary This PR introduces **Focus Reading**, a generic implementation of artificial fixation points (similar to Bionic Reading) designed to improve reading speed and focus by bolding the initial characters of words. This is achieved by dynamically bolding characters during indexing. <img width="500" alt="Focus Reading on X3" src="https://github.com/user-attachments/assets/94a632a5-82da-47be-957c-538b35bf84d9" /> ### Implementation Details #### Core Text Engine (`ParsedText`) - Modified `ParsedText::addWord` to implement a custom bolding algorithm. It uses a 45% ratio for bolding, with a minimum of 1 character and a maximum of 9. - UTF-8 Safety: Integrated `utf8NextCodepoint` to ensure character counting and string slicing occur at safe byte boundaries, preventing corruption of multi-byte characters (e.g., accented letters or smart quotes). - Intelligent Tokenization: This correctly identifies and separates "word" characters (letters, apostrophes, hyphens) from "non-word" characters (numbers, brackets, smart quotes). - Formatting Preservation: The logic ensures that punctuation is not "stolen" for the bolding count and that existing styles (like italics or underlines) are preserved across the bold/regular split. - Processing at indexing stage reduces CPU load at render-time and ensures layout/fit is unaffected. - Split details are tracked with `wordIsFocusSuffix`. After splitting and layout, suffixes are merged back into their preceding word entries to prevent a doubling of RAM usage. #### Settings and UI - Version Management: Bumped `SECTION_FILE_VERSION` to `21` - Global Settings: Added `focusReadingEnabled` to `CrossPointSettings`. - User Interface: Added a new toggle in the "Reader" section of the settings menu, positioned after the "Embedded Style" option. - Localization: Added the `STR_FOCUS_READING` string #### Plumbing - Plumbed the `focusReadingEnabled` boolean through `EpubReaderActivity`, `Section`, and `ChapterHtmlSlimParser` to ensure the user's setting reaches the `ParsedText` constructor during chapter indexing. ## Additional Context ### Files Changed - `lib/Epub/Epub/ParsedText.h / .cpp`: Core fixation logic and UTF-8 tokenization. - `lib/Epub/Epub/Section.h / .cpp`: Cache header updates and invalidation logic. - `lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h / .cpp`: Plumbing the setting to text blocks. - `src/CrossPointSettings.h`: Data persistence for the new setting. - `src/SettingsList.h`: UI toggle implementation. - `src/activities/reader/EpubReaderActivity.cpp`: Handling settings changes during reading sessions. - `lib/I18n/translations/*.yaml`: UI strings. --- ### 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? _**YES**_
300 lines
11 KiB
YAML
300 lines
11 KiB
YAML
_language_name: "Français"
|
||
_language_code: "FR"
|
||
_order: "2"
|
||
|
||
STR_CROSSPOINT: "CrossPoint"
|
||
STR_BOOTING: "DÉMARRAGE EN COURS"
|
||
STR_SLEEPING: "VEILLE"
|
||
STR_ENTERING_SLEEP: "Mise en veille"
|
||
STR_BROWSE_FILES: "Parcourir les fichiers"
|
||
STR_FILE_TRANSFER: "Transfert de fichiers"
|
||
STR_SETTINGS_TITLE: "Réglages"
|
||
STR_CONTINUE_READING: "Reprendre la lecture"
|
||
STR_NO_OPEN_BOOK: "Aucun livre ouvert"
|
||
STR_START_READING: "Commencer la lecture"
|
||
STR_NO_FILES_FOUND: "Aucun fichier trouvé"
|
||
STR_SELECT_CHAPTER: "Choix du chapitre"
|
||
STR_NO_CHAPTERS: "Aucun chapitre"
|
||
STR_END_OF_BOOK: "Fin du livre"
|
||
STR_EMPTY_CHAPTER: "Chapitre vide"
|
||
STR_INDEXING: "Indexation en cours"
|
||
STR_MEMORY_ERROR: "Erreur de mémoire"
|
||
STR_PAGE_LOAD_ERROR: "Erreur de chargement"
|
||
STR_EMPTY_FILE: "Fichier vide"
|
||
STR_OUT_OF_BOUNDS: "Dépassement de mémoire"
|
||
STR_LOADING: "Chargement…"
|
||
STR_LOADING_POPUP: "Chargement"
|
||
STR_WIFI_NETWORKS: "Réseaux WiFi"
|
||
STR_NO_NETWORKS: "Aucun réseau"
|
||
STR_NETWORKS_FOUND: "%zu réseaux"
|
||
STR_SCANNING: "Recherche en cours…"
|
||
STR_CONNECTING: "Connexion en cours…"
|
||
STR_CONNECTED: "Connecté !"
|
||
STR_CONNECTION_FAILED: "Échec de la connexion"
|
||
STR_FORGET_NETWORK: "Oublier ce réseau ?"
|
||
STR_SAVE_PASSWORD: "Enregistrer le mot de passe ?"
|
||
STR_PRESS_OK_SCAN: "Appuyez sur OK pour scanner"
|
||
STR_JOIN_NETWORK: "Rejoindre un réseau"
|
||
STR_CREATE_HOTSPOT: "Créer un point d’accès"
|
||
STR_JOIN_DESC: "Se connecter à un WiFi existant"
|
||
STR_HOTSPOT_DESC: "Créer un WiFi pour d'autres appareils"
|
||
STR_STARTING_HOTSPOT: "Création du point d’accès…"
|
||
STR_HOTSPOT_MODE: "Mode point d’accès"
|
||
STR_CONNECT_WIFI_HINT: "Connectez un appareil à ce WiFi"
|
||
STR_OPEN_URL_HINT: "Ouvrez cette URL dans un navigateur"
|
||
STR_OR_HTTP_PREFIX: "ou http://"
|
||
STR_SCAN_QR_HINT: "ou scannez le QR code :"
|
||
STR_CALIBRE_WIRELESS: "Connexion Calibre sans fil"
|
||
STR_CALIBRE_WEB_URL: "OPDS URL"
|
||
STR_NETWORK_LEGEND: "* = Sécurisé | + = Sauvegardé"
|
||
STR_MAC_ADDRESS: "Adresse MAC :"
|
||
STR_CHECKING_WIFI: "Vérification du WiFi…"
|
||
STR_ENTER_WIFI_PASSWORD: "Entrez le mot de passe WiFi"
|
||
STR_TO_PREFIX: "vers "
|
||
STR_CALIBRE_RECEIVING: "Réception : "
|
||
STR_CALIBRE_RECEIVED: "Reçu : "
|
||
STR_CALIBRE_INSTRUCTION_1: "1) Installer plugin CrossPoint Reader"
|
||
STR_CALIBRE_INSTRUCTION_2: "2) Être sur le même réseau WiFi"
|
||
STR_CALIBRE_INSTRUCTION_3: "3) Calibre : ‘Envoyer vers l’appareil’"
|
||
STR_CALIBRE_INSTRUCTION_4: "4) Gardez cet écran ouvert"
|
||
STR_CAT_DISPLAY: "Affichage"
|
||
STR_CAT_READER: "Lecteur"
|
||
STR_CAT_CONTROLS: "Commandes"
|
||
STR_CAT_SYSTEM: "Système"
|
||
STR_SLEEP_SCREEN: "Écran de veille"
|
||
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"
|
||
STR_LONG_PRESS_BEHAVIOR: "Comportement lors d'un appui long"
|
||
STR_LONG_PRESS_BEHAVIOR_OFF: "Désactivé"
|
||
STR_LONG_PRESS_BEHAVIOR_SKIP: "Saut de chapitre"
|
||
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Changement d'orientation"
|
||
STR_FONT_FAMILY: "Police de caractères du lecteur"
|
||
STR_FONT_SIZE: "Taille texte interface"
|
||
STR_LINE_SPACING: "Interligne"
|
||
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"
|
||
STR_LANGUAGE: "Langue"
|
||
STR_CLEAR_READING_CACHE: "Vider le cache de lecture"
|
||
STR_USERNAME: "Nom d’utilisateur"
|
||
STR_PASSWORD: "Mot de passe"
|
||
STR_SYNC_SERVER_URL: "URL du serveur"
|
||
STR_DOCUMENT_MATCHING: "Correspondance"
|
||
STR_AUTHENTICATE: "Connexion"
|
||
STR_KOREADER_USERNAME: "Utilisateur"
|
||
STR_KOREADER_PASSWORD: "Mot de passe"
|
||
STR_FILENAME: "Nom de fichier"
|
||
STR_BINARY: "Binaire"
|
||
STR_SET_CREDENTIALS_FIRST: "Identifiants manquants"
|
||
STR_WIFI_CONN_FAILED: "Échec connexion WiFi"
|
||
STR_AUTHENTICATING: "Authentification…"
|
||
STR_AUTH_SUCCESS: "Authentifié !"
|
||
STR_KOREADER_AUTH: "Auth KOReader"
|
||
STR_SYNC_READY: "Synchro KOReader prête"
|
||
STR_AUTH_FAILED: "Échec authentification"
|
||
STR_DONE: "Fait"
|
||
STR_CLEAR_CACHE_WARNING_1: "Le cache de la bibliothèque sera vidé."
|
||
STR_CLEAR_CACHE_WARNING_2: "Votre progression sera perdue !"
|
||
STR_CLEAR_CACHE_WARNING_3: "Les livres devront être réindexés"
|
||
STR_CLEAR_CACHE_WARNING_4: "à la prochaine ouverture."
|
||
STR_CLEARING_CACHE: "Nettoyage du cache…"
|
||
STR_CACHE_CLEARED: "Cache vidé"
|
||
STR_ITEMS_REMOVED: "éléments supprimés"
|
||
STR_FAILED_LOWER: "ont échoué"
|
||
STR_CLEAR_CACHE_FAILED: "Échec nettoyage cache"
|
||
STR_CHECK_SERIAL_OUTPUT: "Voir console pour détails"
|
||
STR_DARK: "Sombre"
|
||
STR_LIGHT: "Clair"
|
||
STR_CUSTOM: "Personnalisé"
|
||
STR_COVER: "Couverture"
|
||
STR_NONE_OPT: "Aucun"
|
||
STR_FIT: "Ajusté"
|
||
STR_CROP: "Rogné"
|
||
STR_NEVER: "Jamais"
|
||
STR_IN_READER: "Dans le lecteur"
|
||
STR_ALWAYS: "Toujours"
|
||
STR_IGNORE: "Ignorer"
|
||
STR_SLEEP: "Mise en veille"
|
||
STR_PAGE_TURN: "Page suivante"
|
||
STR_PORTRAIT: "Portrait"
|
||
STR_LANDSCAPE_CW: "Paysage"
|
||
STR_INVERTED: "Inversé"
|
||
STR_LANDSCAPE_CCW: "Paysage inversé"
|
||
STR_PREV_NEXT: "Préc/Suiv"
|
||
STR_NEXT_PREV: "Suiv/Préc"
|
||
STR_NOTO_SERIF: "Noto Serif"
|
||
STR_NOTO_SANS: "Noto Sans"
|
||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||
STR_SMALL: "Petit"
|
||
STR_MEDIUM: "Moyen"
|
||
STR_LARGE: "Grand"
|
||
STR_X_LARGE: "Très grand"
|
||
STR_TIGHT: "Serré"
|
||
STR_NORMAL: "Normal"
|
||
STR_WIDE: "Large"
|
||
STR_JUSTIFY: "Justifié"
|
||
STR_ALIGN_LEFT: "Gauche"
|
||
STR_CENTER: "Centré"
|
||
STR_ALIGN_RIGHT: "Droite"
|
||
STR_MIN_1: "1 min"
|
||
STR_MIN_5: "5 min"
|
||
STR_MIN_10: "10 min"
|
||
STR_MIN_15: "15 min"
|
||
STR_MIN_30: "30 min"
|
||
STR_PAGES_1: "1 page"
|
||
STR_PAGES_5: "5 pages"
|
||
STR_PAGES_10: "10 pages"
|
||
STR_PAGES_15: "15 pages"
|
||
STR_PAGES_30: "30 pages"
|
||
STR_UPDATE: "Mise à jour"
|
||
STR_CHECKING_UPDATE: "Recherche de mise à jour…"
|
||
STR_NEW_UPDATE: "Mise à jour disponible !"
|
||
STR_CURRENT_VERSION: "Version actuelle :"
|
||
STR_NEW_VERSION: "Nouvelle version : "
|
||
STR_UPDATING: "Mise à jour en cours…"
|
||
STR_NO_UPDATE: "Aucune mise à jour"
|
||
STR_UPDATE_FAILED: "Échec de la mise à jour"
|
||
STR_UPDATE_COMPLETE: "Mise à jour effectuée"
|
||
STR_POWER_ON_HINT: "Maintenir Power pour redémarrer"
|
||
STR_NO_ENTRIES: "Aucune entrée"
|
||
STR_DOWNLOADING: "Téléchargement…"
|
||
STR_DOWNLOAD_FAILED: "Échec du téléchargement"
|
||
STR_ERROR_MSG: "Erreur : "
|
||
STR_UNNAMED: "Sans titre"
|
||
STR_NO_SERVER_URL: "URL serveur non configurée"
|
||
STR_FETCH_FEED_FAILED: "Échec récupération flux"
|
||
STR_PARSE_FEED_FAILED: "Échec analyse flux"
|
||
STR_NETWORK_PREFIX: "Réseau : "
|
||
STR_IP_ADDRESS_PREFIX: "IP : "
|
||
STR_ERROR_GENERAL_FAILURE: "Erreur : Échec général"
|
||
STR_ERROR_NETWORK_NOT_FOUND: "Erreur : Réseau introuvable"
|
||
STR_ERROR_CONNECTION_TIMEOUT: "Erreur : Délai dépassé"
|
||
STR_SD_CARD: "Carte SD"
|
||
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"
|
||
STR_CONNECT: "Connecter"
|
||
STR_OPEN: "Ouvrir"
|
||
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"
|
||
STR_DIR_LEFT: "Gauche"
|
||
STR_DIR_RIGHT: "Droite"
|
||
STR_DIR_UP: "Haut"
|
||
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"
|
||
STR_THEME_ROUNDEDRAFF: "RoundedRaff"
|
||
STR_THEME_LYRA_EXTENDED: "Lyra Extended"
|
||
STR_SUNLIGHT_FADING_FIX: "Correction lisibilité au soleil"
|
||
STR_REMAP_FRONT_BUTTONS: "Configurer boutons façade"
|
||
STR_OPDS_BROWSER: "Navigateur OPDS"
|
||
STR_COVER_CUSTOM: "Couverture + Perso"
|
||
STR_MENU_RECENT_BOOKS: "Livres récents"
|
||
STR_NO_RECENT_BOOKS: "Aucun livre récent"
|
||
STR_CALIBRE_DESC: "Utiliser transfert sans fil Calibre"
|
||
STR_FORGET_AND_REMOVE: "Oublier le réseau et le mot de passe ?"
|
||
STR_FORGET_BUTTON: "Oublier"
|
||
STR_CALIBRE_STARTING: "Démarrage Calibre…"
|
||
STR_CALIBRE_SETUP: "Configuration"
|
||
STR_CALIBRE_STATUS: "Statut"
|
||
STR_CLEAR_BUTTON: "Effacer"
|
||
STR_DEFAULT_VALUE: "Défaut"
|
||
STR_REMAP_PROMPT: "Appuyez sur un bouton façade"
|
||
STR_UNASSIGNED: "Non assigné"
|
||
STR_ALREADY_ASSIGNED: "Déjà assigné"
|
||
STR_REMAP_RESET_HINT: "Latéral haut : Réinitialiser"
|
||
STR_REMAP_CANCEL_HINT: "Latéral bas : Annuler"
|
||
STR_HW_BACK_LABEL: "Retour (Bouton 1)"
|
||
STR_HW_CONFIRM_LABEL: "OK (Bouton 2)"
|
||
STR_HW_LEFT_LABEL: "Gauche (Bouton 3)"
|
||
STR_HW_RIGHT_LABEL: "Droite (Bouton 4)"
|
||
STR_GO_TO_PERCENT: "Aller à %"
|
||
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 : "
|
||
STR_CALIBRE_URL_HINT: "Pour Calibre, ajoutez /opds à l’URL"
|
||
STR_PERCENT_STEP_HINT: "Gauche/Droite : 1% Haut/Bas : 10%"
|
||
STR_SYNCING_TIME: "Synchro de l’heure…"
|
||
STR_CALC_HASH: "Calcul hash doc…"
|
||
STR_HASH_FAILED: "Échec calcul hash"
|
||
STR_FETCH_PROGRESS: "Téléchargement progression…"
|
||
STR_UPLOAD_PROGRESS: "Envoi progression…"
|
||
STR_NO_CREDENTIALS_MSG: "Aucun identifiant"
|
||
STR_KOREADER_SETUP_HINT: "Configurer compte KOReader dans réglages"
|
||
STR_PROGRESS_FOUND: "Progression trouvée !"
|
||
STR_REMOTE_LABEL: "En ligne :"
|
||
STR_LOCAL_LABEL: "Local :"
|
||
STR_PAGE_OVERALL_FORMAT: "Page %d, %.2f%% total"
|
||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Page %d/%d, %.2f%% total"
|
||
STR_DEVICE_FROM_FORMAT: " De : %s"
|
||
STR_APPLY_REMOTE: "Appliquer progression en ligne"
|
||
STR_UPLOAD_LOCAL: "Envoyer progression locale"
|
||
STR_NO_REMOTE_MSG: "Aucune progression en ligne"
|
||
STR_UPLOAD_PROMPT: "Envoyer position actuelle ?"
|
||
STR_UPLOAD_SUCCESS: "Progression envoyée !"
|
||
STR_SYNC_FAILED_MSG: "Échec de la synchro"
|
||
STR_SAVE_PROGRESS_FAILED: "Échec de l'enregistrement"
|
||
STR_SECTION_PREFIX: "Section "
|
||
STR_UPLOAD: "Envoyer"
|
||
STR_BOOK_S_STYLE: "Style du livre"
|
||
STR_EMBEDDED_STYLE: "Style intégré"
|
||
STR_FOCUS_READING: "Lecture focalisée"
|
||
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)"
|
||
STR_TILT_PAGE_TURN: "Tourner par inclinaison"
|