## 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**_
269 lines
10 KiB
YAML
269 lines
10 KiB
YAML
_language_name: "Suomi"
|
|
_language_code: "FI"
|
|
_order: "14"
|
|
|
|
STR_CROSSPOINT: "CrossPoint"
|
|
STR_BOOTING: "KÄYNNISTYY"
|
|
STR_SLEEPING: "LEPOTILA"
|
|
STR_ENTERING_SLEEP: "Siirrytään lepotilaan"
|
|
STR_BROWSE_FILES: "Selaa tiedostoja"
|
|
STR_FILE_TRANSFER: "Tiedostonsiirto"
|
|
STR_SETTINGS_TITLE: "Asetukset"
|
|
STR_CONTINUE_READING: "Jatka lukemista"
|
|
STR_NO_OPEN_BOOK: "Kirjaa ei valittu"
|
|
STR_START_READING: "Aloita lukeminen"
|
|
STR_NO_FILES_FOUND: "Ei tiedostoja löytynyt"
|
|
STR_SELECT_CHAPTER: "Valitse luku"
|
|
STR_NO_CHAPTERS: "Ei lukuja"
|
|
STR_END_OF_BOOK: "Kirjan loppu"
|
|
STR_EMPTY_CHAPTER: "Tyhjä luku"
|
|
STR_INDEXING: "Indeksoidaan"
|
|
STR_MEMORY_ERROR: "Muistivirhe"
|
|
STR_PAGE_LOAD_ERROR: "Sivun latausvirhe"
|
|
STR_EMPTY_FILE: "Tyhjä tiedosto"
|
|
STR_OUT_OF_BOUNDS: "Alueen ulkopuolella"
|
|
STR_LOADING: "Ladataan..."
|
|
STR_LOADING_POPUP: "Ladataan"
|
|
STR_WIFI_NETWORKS: "WiFi-verkot"
|
|
STR_NO_NETWORKS: "Verkkoja ei löytynyt"
|
|
STR_NETWORKS_FOUND: "%zu verkkoa löydetty"
|
|
STR_SCANNING: "Etsitään..."
|
|
STR_CONNECTING: "Yhdistetään..."
|
|
STR_CONNECTED: "Yhdistetty!"
|
|
STR_CONNECTION_FAILED: "Yhteys epäonnistui"
|
|
STR_FORGET_NETWORK: "Unohda verkko?"
|
|
STR_SAVE_PASSWORD: "Tallenna salasana seuraavaa kertaa varten?"
|
|
STR_PRESS_OK_SCAN: "Paina OK etsiäksesi uudelleen"
|
|
STR_JOIN_NETWORK: "Liity verkkoon"
|
|
STR_CREATE_HOTSPOT: "Luo yhteyspiste"
|
|
STR_JOIN_DESC: "Yhdistä olemassa olevaan WiFi-verkkoon"
|
|
STR_HOTSPOT_DESC: "Luo WiFi-verkko, johon muut voivat liittyä"
|
|
STR_STARTING_HOTSPOT: "Käynnistetään yhteyspiste..."
|
|
STR_HOTSPOT_MODE: "Yhteyspistetila"
|
|
STR_CONNECT_WIFI_HINT: "Yhdistä laitteesi tähän WiFi-verkkoon"
|
|
STR_OPEN_URL_HINT: "Avaa tämä osoite selaimessasi"
|
|
STR_OR_HTTP_PREFIX: "tai http://"
|
|
STR_SCAN_QR_HINT: "tai skannaa QR-koodi puhelimellasi:"
|
|
STR_CALIBRE_WIRELESS: "Calibre langaton"
|
|
STR_CALIBRE_WEB_URL: "OPDS URL"
|
|
STR_NETWORK_LEGEND: "* = Salattu | + = Tallennettu"
|
|
STR_MAC_ADDRESS: "MAC-osoite:"
|
|
STR_CHECKING_WIFI: "Tarkistetaan WiFi..."
|
|
STR_ENTER_WIFI_PASSWORD: "Syötä WiFi-salasana"
|
|
STR_TO_PREFIX: "verkkoon "
|
|
STR_CALIBRE_RECEIVING: "Vastaanotetaan: "
|
|
STR_CALIBRE_RECEIVED: "Vastaanotettu: "
|
|
STR_CALIBRE_INSTRUCTION_1: "1) Asenna CrossPoint Reader -lisäosa"
|
|
STR_CALIBRE_INSTRUCTION_2: "2) Ole samassa WiFi-verkossa"
|
|
STR_CALIBRE_INSTRUCTION_3: "3) Calibressa: \"Lähetä laitteelle\""
|
|
STR_CALIBRE_INSTRUCTION_4: "\"Pidä tämä näyttö auki lähetyksen aikana\""
|
|
STR_CAT_DISPLAY: "Näyttö"
|
|
STR_CAT_READER: "Lukija"
|
|
STR_CAT_CONTROLS: "Ohjaimet"
|
|
STR_CAT_SYSTEM: "Järjestelmä"
|
|
STR_SLEEP_SCREEN: "Lepotilanäyttö"
|
|
STR_SLEEP_COVER_MODE: "Lepotilanäytön kansitila"
|
|
STR_HIDE_BATTERY: "Piilota akun %"
|
|
STR_EXTRA_SPACING: "Kappaleiden lisäväli"
|
|
STR_TEXT_AA: "Tekstin reunanpehmennys"
|
|
STR_SHORT_PWR_BTN: "Lyhyt virtapainikkeen painallus"
|
|
STR_ORIENTATION: "Lukusuunta"
|
|
STR_SIDE_BTN_LAYOUT: "Sivupainikkeiden asettelu (lukija)"
|
|
STR_LONG_PRESS_BEHAVIOR: "Long-press button behavior"
|
|
STR_LONG_PRESS_BEHAVIOR_OFF: "OFF"
|
|
STR_LONG_PRESS_BEHAVIOR_SKIP: "Chapter skip"
|
|
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Orientation change"
|
|
STR_FONT_FAMILY: "Lukijan fonttiperhe"
|
|
STR_FONT_SIZE: "Käyttöliittymän fonttikoko"
|
|
STR_LINE_SPACING: "Lukijan riviväli"
|
|
STR_SCREEN_MARGIN: "Lukijan näyttömarginaali"
|
|
STR_PARA_ALIGNMENT: "Lukijan kappaletasaus"
|
|
STR_HYPHENATION: "Tavutus"
|
|
STR_TIME_TO_SLEEP: "Aika lepotilaan"
|
|
STR_REFRESH_FREQ: "Päivitystaajuus"
|
|
STR_KOREADER_SYNC: "KOReader-synkronointi"
|
|
STR_CHECK_UPDATES: "Tarkista päivitykset"
|
|
STR_LANGUAGE: "Kieli"
|
|
STR_CLEAR_READING_CACHE: "Tyhjennä lukuvälimuisti"
|
|
STR_USERNAME: "Käyttäjänimi"
|
|
STR_PASSWORD: "Salasana"
|
|
STR_SYNC_SERVER_URL: "Synkronointipalvelimen osoite"
|
|
STR_DOCUMENT_MATCHING: "Dokumenttien tunnistus"
|
|
STR_AUTHENTICATE: "Tunnistaudu"
|
|
STR_KOREADER_USERNAME: "KOReader-käyttäjänimi"
|
|
STR_KOREADER_PASSWORD: "KOReader-salasana"
|
|
STR_FILENAME: "Tiedostonimi"
|
|
STR_BINARY: "Binääri"
|
|
STR_SET_CREDENTIALS_FIRST: "Aseta tunnukset ensin"
|
|
STR_WIFI_CONN_FAILED: "WiFi-yhteys epäonnistui"
|
|
STR_AUTHENTICATING: "Tunnistaudutaan..."
|
|
STR_AUTH_SUCCESS: "Tunnistautuminen onnistui!"
|
|
STR_KOREADER_AUTH: "KOReader-tunnistautuminen"
|
|
STR_SYNC_READY: "KOReader-synkronointi on käyttövalmis"
|
|
STR_AUTH_FAILED: "Tunnistautuminen epäonnistui"
|
|
STR_DONE: "Valmis"
|
|
STR_CLEAR_CACHE_WARNING_1: "Tämä tyhjentää kaiken välimuistiin tallennetun kirjatiedon."
|
|
STR_CLEAR_CACHE_WARNING_2: "Kaikki lukuedistyminen menetetään!"
|
|
STR_CLEAR_CACHE_WARNING_3: "Kirjat täytyy indeksoida uudelleen"
|
|
STR_CLEAR_CACHE_WARNING_4: "kun ne avataan seuraavan kerran."
|
|
STR_CLEARING_CACHE: "Tyhjennetään välimuistia..."
|
|
STR_CACHE_CLEARED: "Välimuisti tyhjennetty"
|
|
STR_ITEMS_REMOVED: "kohdetta poistettu"
|
|
STR_FAILED_LOWER: "epäonnistui"
|
|
STR_CLEAR_CACHE_FAILED: "Välimuistin tyhjennys epäonnistui"
|
|
STR_CHECK_SERIAL_OUTPUT: "Tarkista sarjatuloste lisätiedoista"
|
|
STR_DARK: "Tumma"
|
|
STR_LIGHT: "Vaalea"
|
|
STR_CUSTOM: "Mukautettu"
|
|
STR_COVER: "Kansi"
|
|
STR_NONE_OPT: "Ei mitään"
|
|
STR_FIT: "Sovita"
|
|
STR_CROP: "Rajaa"
|
|
STR_NEVER: "Ei koskaan"
|
|
STR_IN_READER: "Lukijassa"
|
|
STR_ALWAYS: "Aina"
|
|
STR_IGNORE: "Ohita"
|
|
STR_SLEEP: "Lepotila"
|
|
STR_PAGE_TURN: "Sivunkääntö"
|
|
STR_PORTRAIT: "Pysty"
|
|
STR_LANDSCAPE_CW: "Vaaka myötäpäivään"
|
|
STR_INVERTED: "Käännetty"
|
|
STR_LANDSCAPE_CCW: "Vaaka vastapäivään"
|
|
STR_PREV_NEXT: "Edell/Seur"
|
|
STR_NEXT_PREV: "Seur/Edell"
|
|
STR_NOTO_SERIF: "Noto Serif"
|
|
STR_NOTO_SANS: "Noto Sans"
|
|
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
|
STR_SMALL: "Pieni"
|
|
STR_MEDIUM: "Keskikokoinen"
|
|
STR_LARGE: "Suuri"
|
|
STR_X_LARGE: "Erittäin suuri"
|
|
STR_TIGHT: "Tiukka"
|
|
STR_NORMAL: "Normaali"
|
|
STR_WIDE: "Leveä"
|
|
STR_JUSTIFY: "Tasaa"
|
|
STR_ALIGN_LEFT: "Vasen"
|
|
STR_CENTER: "Keskitetty"
|
|
STR_ALIGN_RIGHT: "Oikea"
|
|
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 sivu"
|
|
STR_PAGES_5: "5 sivua"
|
|
STR_PAGES_10: "10 sivua"
|
|
STR_PAGES_15: "15 sivua"
|
|
STR_PAGES_30: "30 sivua"
|
|
STR_UPDATE: "Päivitä"
|
|
STR_CHECKING_UPDATE: "Tarkistetaan päivitystä..."
|
|
STR_NEW_UPDATE: "Uusi päivitys saatavilla!"
|
|
STR_CURRENT_VERSION: "Nykyinen versio: "
|
|
STR_NEW_VERSION: "Uusi versio: "
|
|
STR_UPDATING: "Päivitetään..."
|
|
STR_NO_UPDATE: "Ei päivitystä saatavilla"
|
|
STR_UPDATE_FAILED: "Päivitys epäonnistui"
|
|
STR_UPDATE_COMPLETE: "Päivitys valmis"
|
|
STR_POWER_ON_HINT: "Pidä virtapainiketta pohjassa käynnistääksesi"
|
|
STR_NO_ENTRIES: "Merkintöjä ei löytynyt"
|
|
STR_DOWNLOADING: "Ladataan..."
|
|
STR_DOWNLOAD_FAILED: "Lataus epäonnistui"
|
|
STR_ERROR_MSG: "Virhe:"
|
|
STR_UNNAMED: "Nimetön"
|
|
STR_NO_SERVER_URL: "Palvelinosoitetta ei ole määritetty"
|
|
STR_FETCH_FEED_FAILED: "Syötteen haku epäonnistui"
|
|
STR_PARSE_FEED_FAILED: "Syötteen käsittely epäonnistui"
|
|
STR_NETWORK_PREFIX: "Verkko: "
|
|
STR_IP_ADDRESS_PREFIX: "IP-osoite: "
|
|
STR_ERROR_GENERAL_FAILURE: "Virhe: Yleinen virhe"
|
|
STR_ERROR_NETWORK_NOT_FOUND: "Virhe: Verkkoa ei löytynyt"
|
|
STR_ERROR_CONNECTION_TIMEOUT: "Virhe: Yhteys aikakatkaistiin"
|
|
STR_SD_CARD: "SD-kortti"
|
|
STR_BACK: "« Takaisin"
|
|
STR_EXIT: "« Poistu"
|
|
STR_HOME: "« Koti"
|
|
STR_SELECT: "Valitse"
|
|
STR_TOGGLE: "Vaihda"
|
|
STR_CONFIRM: "Vahvista"
|
|
STR_CANCEL: "Peruuta"
|
|
STR_CONNECT: "Yhdistä"
|
|
STR_OPEN: "Avaa"
|
|
STR_DOWNLOAD: "Lataa"
|
|
STR_RETRY: "Yritä uudelleen"
|
|
STR_YES: "Kyllä"
|
|
STR_NO: "Ei"
|
|
STR_STATE_ON: "PÄÄLLÄ"
|
|
STR_STATE_OFF: "POIS"
|
|
STR_NOT_SET: "Ei asetettu"
|
|
STR_DIR_LEFT: "Vasen"
|
|
STR_DIR_RIGHT: "Oikea"
|
|
STR_DIR_UP: "Ylös"
|
|
STR_DIR_DOWN: "Alas"
|
|
STR_OK_BUTTON: "OK"
|
|
STR_SLEEP_COVER_FILTER: "Lepotilanäytön kansisuodatin"
|
|
STR_FILTER_CONTRAST: "Kontrasti"
|
|
STR_UI_THEME: "Käyttöliittymäteema"
|
|
STR_THEME_CLASSIC: "Klassinen"
|
|
STR_THEME_LYRA: "Lyra"
|
|
STR_THEME_LYRA_EXTENDED: "Lyra Extended"
|
|
STR_SUNLIGHT_FADING_FIX: "Auringonvalon haalistumiskorjaus"
|
|
STR_REMAP_FRONT_BUTTONS: "Uudelleenmääritä etupainikkeet"
|
|
STR_OPDS_BROWSER: "OPDS-selain"
|
|
STR_COVER_CUSTOM: "Kansi + mukautettu"
|
|
STR_MENU_RECENT_BOOKS: "Viimeisimmät kirjat"
|
|
STR_NO_RECENT_BOOKS: "Ei viimeisimpiä kirjoja"
|
|
STR_CALIBRE_DESC: "Käytä Calibren langatonta laiteyhteyttä"
|
|
STR_FORGET_AND_REMOVE: "Unohda verkko ja poista tallennettu salasana?"
|
|
STR_FORGET_BUTTON: "Unohda"
|
|
STR_CALIBRE_STARTING: "Käynnistetään Calibrea..."
|
|
STR_CALIBRE_SETUP: "Asetukset"
|
|
STR_CALIBRE_STATUS: "Tila"
|
|
STR_CLEAR_BUTTON: "Tyhjennä"
|
|
STR_DEFAULT_VALUE: "Oletus"
|
|
STR_REMAP_PROMPT: "Paina etupainiketta kullekin toiminnolle"
|
|
STR_UNASSIGNED: "Ei määritetty"
|
|
STR_ALREADY_ASSIGNED: "Jo määritetty"
|
|
STR_REMAP_RESET_HINT: "Sivupainike ylös: Palauta oletusasettelu"
|
|
STR_REMAP_CANCEL_HINT: "Sivupainike alas: Peruuta uudelleenmääritys"
|
|
STR_HW_BACK_LABEL: "Takaisin (1. painike)"
|
|
STR_HW_CONFIRM_LABEL: "Vahvista (2. painike)"
|
|
STR_HW_LEFT_LABEL: "Vasen (3. painike)"
|
|
STR_HW_RIGHT_LABEL: "Oikea (4. painike)"
|
|
STR_GO_TO_PERCENT: "Siirry kohtaan %"
|
|
STR_GO_HOME_BUTTON: "Siirry kotiin"
|
|
STR_SYNC_PROGRESS: "Synkronoi edistyminen"
|
|
STR_DELETE_CACHE: "Poista kirjan välimuisti"
|
|
STR_CHAPTER_PREFIX: "Luku: "
|
|
STR_PAGES_SEPARATOR: " sivua | "
|
|
STR_BOOK_PREFIX: "Kirja: "
|
|
STR_CALIBRE_URL_HINT: "Calibrelle lisää /opds osoitteeseen"
|
|
STR_PERCENT_STEP_HINT: "Vasen/Oikea: 1% Ylös/Alas: 10%"
|
|
STR_SYNCING_TIME: "Synkronoidaan aikaa..."
|
|
STR_CALC_HASH: "Lasketaan dokumentin tarkistussummaa..."
|
|
STR_HASH_FAILED: "Dokumentin tiivisteen laskenta epäonnistui"
|
|
STR_FETCH_PROGRESS: "Haetaan etäedistymistä..."
|
|
STR_UPLOAD_PROGRESS: "Lähetetään lukuedistymistä..."
|
|
STR_NO_CREDENTIALS_MSG: "Tunnuksia ei ole määritetty"
|
|
STR_KOREADER_SETUP_HINT: "Määritä KOReader-tili asetuksissa"
|
|
STR_PROGRESS_FOUND: "Edistyminen löytyi!"
|
|
STR_REMOTE_LABEL: "Etä:"
|
|
STR_LOCAL_LABEL: "Paikallinen:"
|
|
STR_PAGE_OVERALL_FORMAT: "Sivu %d, %.2f%% kokonaisuudesta"
|
|
STR_PAGE_TOTAL_OVERALL_FORMAT: "Sivu %d/%d, %.2f%% kokonaisuudesta"
|
|
STR_DEVICE_FROM_FORMAT: " Lähde: %s"
|
|
STR_APPLY_REMOTE: "Käytä etäedistymistä"
|
|
STR_UPLOAD_LOCAL: "Lähetä paikallinen edistyminen"
|
|
STR_NO_REMOTE_MSG: "Etäedistymistä ei löytynyt"
|
|
STR_UPLOAD_PROMPT: "Lähetä nykyinen sijainti?"
|
|
STR_UPLOAD_SUCCESS: "Edistyminen lähetetty!"
|
|
STR_SYNC_FAILED_MSG: "Synkronointi epäonnistui"
|
|
STR_SAVE_PROGRESS_FAILED: "Edistymisen tallennus epäonnistui"
|
|
STR_SECTION_PREFIX: "Osio "
|
|
STR_UPLOAD: "Lähetä"
|
|
STR_BOOK_S_STYLE: "Kirjan tyyli"
|
|
STR_EMBEDDED_STYLE: "Upotettu tyyli"
|
|
STR_FOCUS_READING: "Keskittynyt lukeminen"
|
|
STR_OPDS_SERVER_URL: "OPDS-palvelimen osoite"
|
|
STR_SCREENSHOT_BUTTON: "Ota kuvakaappaus"
|
|
STR_TILT_PAGE_TURN: "Sivunkääntö kallistamalla"
|