Compare commits

...

966 Commits

Author SHA1 Message Date
Huang Xin 3174e341a3 release: version 0.10.4 (#3767) 2026-04-05 19:57:06 +02:00
Huang Xin 298d4872a0 fix(translate): disable yandex provider while upstream relay is down (#3765)
The translate.toil.cc relay that backs the yandex provider is currently
unavailable. Introduce a `disabled` flag on TranslationProvider and
filter disabled providers out of both `getTranslators()` and
`getTranslator()` so the settings panel, translator popup, and the
fallback logic in `useTranslator` all agree the provider doesn't exist —
no per-callsite changes needed. Flip the flag back (or delete the line)
on `yandexProvider` to re-enable once the upstream is healthy.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:48:25 +02:00
Huang Xin b679817fce fix(tts): prevent double playback on rapid TTS icon clicks (#3764)
Guard handleTTSSpeak with a single-flight ref so a second tts-speak
event that arrives while the first is still inside its initial awaits
(initMediaSession / backgroundAudio / TTSController.init) is ignored
instead of racing ahead to construct a second TTSController. Without
this, rapid clicks produced two concurrent speakers talking over each
other because viewState.ttsEnabled is only set at the end of the first
invocation, so the footer bar would dispatch tts-speak twice.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:11:28 +02:00
Huang Xin b9a2b10fac fix(a11y): fixed keyboard activation of dropdown menu (#3762) 2026-04-05 18:48:27 +02:00
Huang Xin a9e33ca50a fix(style): let background texture take precedence over overridden background color (#3761)
When a background texture is active, skip applying the overridden bg/fg/border
colors on block elements so the texture stays visible instead of being painted over.
2026-04-05 18:05:05 +02:00
Huang Xin 09d1e0c040 fix(sync): show last push time as the last sync time (#3760) 2026-04-05 17:55:41 +02:00
Huang Xin 8b10e7fb17 fix(layout): use mobile footer bar in portrait mode without regressing phone panel animation, closes #3742 (#3759)
On mobile tablets/foldables (Android or iOS) in portrait, the viewport
width can exceed the Tailwind \`sm:\` breakpoint (640px), causing the
desktop footer bar to show and hiding the brightness / font size /
color / progress panels that only exist in the mobile layout.

The previous fix in #3746 introduced a regression on phones: wrapping
MobileFooterBar's children in a \`<div>\` changed the flex layout of
the footer container, and panels no longer slid cleanly behind the
navigation bar on dismissal. That PR was reverted.

This re-implementation scopes the override narrowly:

- \`forceMobileLayout\` is only true for mobile devices in portrait
  with innerWidth >= 640. Phones (innerWidth < 640) always get
  \`false\`, so every \`!forceMobileLayout && '…'\` expression
  evaluates to the original class string — phone classNames are
  set-equal to the pre-#3746 version.
- MobileFooterBar keeps its Fragment return; no wrapper div is
  introduced anywhere in the tree, preserving the panel slide-down
  animation exactly as before.
- DesktopFooterBar, NavigationBar, and the three panels
  (ColorPanel / FontLayoutPanel / NavigationPanel) gate their
  \`sm:hidden\` / \`sm:flex\` classes on \`!forceMobileLayout\` so
  they correctly show/hide on wide portrait tablets.
- The orphaned \`.force-mobile-layout\` CSS override in globals.css
  is removed since we no longer rely on a class-based escape hatch.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:40:36 +02:00
Huang Xin a2d17e6a79 fix: clear highlight overlay when deleting annotation from sidebar, closes #3756 (#3758)
The sidebar delete handler always removed annotations through the note
bubble overlay key (`NOTE_PREFIX + cfi`), but highlights are keyed by
the raw CFI. Deleting a highlight from the sidebar therefore left its
overlay drawn until the book was reopened, while the popup path — which
lets `wrappedFoliateView` default the value to the CFI — worked.

Introduce `removeBookNoteOverlays` that mirrors the draw filters in
`Annotator.tsx` and clears every overlay a BookNote can own (highlight
and/or note bubble), and route the sidebar delete through it.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:25:58 +02:00
Huang Xin 7e62516b5d chore(deps): bump Next.js to version 16.2.2 (#3757) 2026-04-05 15:59:10 +02:00
Lex Moulton d53f3b42e2 feat(rsvp): split words option, faster countdown, and skip pages RSVP cant open (#3755)
* fix: use string-parsed year to avoid UTC/timezone boundary issues

* feat: Add option to split words in RSVP mode

* fix: change the checkbox to a toggle

* fix(rsvp): speed up countdown from 2.4s to 1.5s

* feat(rsvp): skip to next page when no readable text is found

* fix(rsvp): replace lookbehind regex with lookahead-only split in getHyphenParts
2026-04-05 14:29:30 +02:00
Mohammed Efaz d682fcbb44 feat: add named highlight colors with sync and picker ux fixes (#3741)
* fix: add highlight color label fields

* fix: add default highlight label sync fields

* fix: add highlight prefs sync helpers

* fix: add highlight color name inputs

* fix: persist and sync highlight color names

* fix: add highlight color label helpers

* fix: add long press highlight label preview

* fix: pull highlight color prefs during library sync

* test: cover highlight color label helpers

* fix: widen highlight color name inputs

* fix: show highlight names on hover and touch hold

* fix: prevent highlight name input overlap

* fix: improve highlight name input responsiveness

* fix: support drag scrolling for highlight colors

* fix: batch custom color and label updates

* fix: serialize highlight prefs saves

* fix: align color strip drag and restore color clicks

* fix: translate default highlight color labels

* refactor: remove highlight preference sync wiring

* fix: align highlight option i18n with existing pattern

* fix: remove redundant english highlight keys

* fix: support raw and normalized highlight label keys

* fix: use underscore translator in highlight options

* fix: translate custom highlight color labels in editor

* refactor: simplify highlight settings persistence

* fix: maintianer review

* refactor: simplify highlight prefs save and clean up editor

- Drop the skipUserColors/skipLabels options from handleHighlightPrefsChange
  and always persist both arrays; the flags only masked a no-op caller.
- Type handleHighlightColorsChange with Record<HighlightColor, string>
  instead of typeof so the signature reads clearly.
- Remove the always-true `|| true` guard around the custom colors section.
- Stop wrapping user-typed custom color labels with _(), matching the
  built-in color inputs and keeping the input value equal to what the
  user typed.

* refactor: couple highlight labels to their colors

Replace the parallel `highlightColorLabels: Record<string, string>` map
with label storage that lives next to each color. This removes the hex
key normalization layer and its whole class of orphan/case-drift bugs.

Data model:
  userHighlightColors: string[]                    ->  UserHighlightColor[]
                                                       ({ hex, label? })
  highlightColorLabels: Record<string, string>     ->  (removed)
                                                       defaultHighlightLabels:
                                                         Partial<Record<DefaultHighlightColor, string>>

A `migrateHighlightColorPrefs` helper runs during `loadSettings` and
handles both the shipped `string[]` layout and the draft-build
`highlightColorLabels` layout: hex-keyed labels attach to matching user
colors, name-keyed labels move into `defaultHighlightLabels`. Malformed
entries are dropped.

Editor:
  - Label inputs commit on blur (Enter also commits), so typing a long
    label no longer fires `setSettings`/`saveSettings` on every
    keystroke. A small `LabelInput` component owns the draft state and
    syncs if the prop changes externally.
  - Three explicit callbacks (`onCustomHighlightColorsChange`,
    `onUserHighlightColorsChange`, `onDefaultHighlightLabelsChange`)
    replace the previous single callback with opaque skip flags.

Picker:
  - Extracted a reusable `useDragScroll` hook (mouse only, 6px
    threshold, 120ms click suppression) from the inline state machine
    in `HighlightOptions`. The picker drops to ~280 lines.
  - Long-press preview stays touch/pen only. It now reads labels via
    `getHighlightColorLabel` (which returns `undefined` when no user
    label is set), letting the component layer decide whether to fall
    back to a translated default name.

i18n:
  - Default color names ('red' | 'yellow' | 'green' | 'blue' | 'violet')
    are registered once at module scope via `stubTranslation` and
    translated at the picker layer through `useTranslation`. User-typed
    labels are never run through `_()`, so what the user types is what
    the editor shows.

Tests:
  - `annotator-util.test.ts`: rewritten around the new helper contract
    (user label -> undefined fallback) and case-insensitive hex matching.
  - `settings-highlight-migration.test.ts`: new, covers legacy
    `string[]`, already-migrated entries, malformed hex filtering, and
    the two draft-label fold paths.

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-04-05 18:08:55 +08:00
Huang Xin b3fe33221d feat(i18n): add Hungarian translation and translate new keys across all locales (#3753)
Add Hungarian (hu) as a new supported locale with full translation coverage.
Also translate the new "Toggle Toolbar" key across all 30 existing locales.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:15:48 +02:00
Huang Xin fbfd7fd6c6 fix(hardcover): use Tauri HTTP plugin to bypass CORS and coerce search result IDs to numbers, closes #3751 (#3752)
The Hardcover GraphQL API rejects requests from tauri://localhost origin on iOS.
Switch to tauriFetch (like KOSyncClient) to bypass CORS in Tauri environments.
Also coerce bookId/editionId/pages from search results to numbers since the
search API returns string IDs but the GraphQL mutations expect 32-bit integers.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:56:47 +02:00
Huang Xin 531dbe5f16 release: version 0.10.2 (#3750) 2026-04-04 21:23:25 +02:00
Huang Xin 70b94d8986 fix(layout): fixed layout of progress bar in vertical mode (#3749) 2026-04-04 21:20:34 +02:00
Huang Xin 21795e5cd3 fix(tts): avoid race condition in preloadNextSSML causing wrong highlights (#3748)
preloadNextSSML() called tts.next() interleaved with await, creating async
gaps where the concurrent #speak() could dispatch marks against corrupted
#ranges state (replaced by next() for a different block). Since mark names
restart at "0" per block, marks resolved to the wrong text position, causing
accidental page turns and highlights far from the current sentence.

Fix: gather all tts.next() and tts.prev() calls synchronously (no await
between them) so no async code can see the intermediate #ranges state.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:42:06 +02:00
Huang Xin 52242d6886 fix(android): use mobile footer bar in portrait mode on Android, closes #3742 (#3746)
On Android tablets/foldables in portrait, screen width can exceed 640px
causing the desktop footer bar to show. Now use portrait orientation
detection to force the mobile footer bar layout on Android regardless
of screen width.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:11:02 +02:00
Huang Xin f361698e05 feat(android): add D-pad navigation for Android TV remote controller (#3745)
* feat(android): add D-pad navigation for Android TV remote controller

Add basic D-pad/arrow key navigation support for Android TV Bluetooth
remote controllers, covering the full flow: library grid browsing,
reader page turning, toolbar interaction, and TTS toggle.

Library:
- Custom spatial navigation hook for grid D-pad navigation
- Arrow keys move between BookshelfItem elements with auto column detection
- ArrowDown from header enters the bookshelf grid

Reader:
- Enter key toggles header/footer toolbar visibility
- Left/Right navigate between toolbar buttons, Up/Down moves between
  header and footer bars
- Back button dismisses toolbar (with blur) before sidebar/library
- Focus-probe technique for reliable button visibility detection
  across fixed/hidden containers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: only auto-focus toolbar buttons on keyboard activation, not mouse hover

Track pointer activity to distinguish keyboard vs mouse toolbar activation.
When the toolbar appears due to mouse hover, skip auto-focus to prevent
unwanted focus outlines on desktop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: track keyboard events instead of pointer events for auto-focus guard

Pointer events from iframes don't bubble to the main document, so
tracking pointermove/pointerdown missed hover interactions over book
content. Track keydown instead — auto-focus only when a recent keyboard
event (Enter key) triggered the toolbar, not mouse hover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:50:34 +02:00
Huang Xin 9595aa56e0 fix(android): get rid of the outline on the header and footer bar when using remote control to turn page (#3744) 2026-04-04 17:00:20 +02:00
Huang Xin caa0d719c5 compat(vertical): check writing mode also for child element of body, closes #3583 (#3743) 2026-04-04 15:56:26 +02:00
Yi-Shun Wang 45bd355981 feat(opds): support custom catalog headers with web proxy consent (#3740)
* Add custom headers support for OPDS catalogs

* Require web proxy consent for sensitive OPDS credentials

* Strengthen OPDS header forwarding tests

---------

Co-authored-by: Yi-Shun Wang <git@albertwang.dev>
2026-04-04 12:01:16 +02:00
Huang Xin 52ac74bbad fix: fixed status info layout in vertical mode, fixed Android build (#3735) 2026-04-03 21:41:49 +02:00
Huang Xin 6a44f609ba fix(paginator): fixed paginator section preloading, closes #3600 and closes #3601 (#3734) 2026-04-03 20:46:45 +02:00
Huang Xin ca5c860594 fix(kosync): don't normalize xpointer for more accurate progress sync, closes #3672 and closes #3616 (#3733) 2026-04-03 16:17:20 +02:00
AK Venugopal 80cab8e56d feat: Hardcover.app Sync (#3724)
* feat(hardcover): add one-way Hardcover sync integration

- Add HardcoverClient with ISBN/title-based book lookup, progress push, and note sync
- Add HardcoverSyncMapStore for persistent local mapping of note IDs to Hardcover journal IDs
- Add GraphQL queries/mutations for Hardcover API (insert/update/recreate journal entries)
- Add DB migration for hardcover_note_mappings table (schema: hardcover-sync)
- Add HardcoverSettings dialog component (connect/disconnect/enable toggle)
- Add useHardcoverSync hook wired in Annotator for push-notes and push-progress events
- Add Hardcover Sync section in BookMenu with per-book toggle (persisted in BookConfig)
- Add HardcoverSettings type and DEFAULT_HARDCOVER_SETTINGS to system settings
- Add hardcoverSyncEnabled per-book flag to BookConfig
- Mount HardcoverSettingsWindow in Reader alongside KOSync and Readwise windows

Sync is one-way (Readest → Hardcover), manual-action only, per-book opt-in.
Supports idempotent note sync: insert new, skip unchanged, update changed, recreate on stale remote ID.

* fix(hardcover): proxy API calls server-side to fix CORS, normalize Bearer token

- Add /api/hardcover/graphql Next.js route that proxies POST requests server-side,
  bypassing CORS restrictions (Hardcover API has no Access-Control-Allow-Origin header)
- On Tauri (desktop), calls Hardcover directly; on web, routes through the proxy
- Normalize token in HardcoverClient: accept raw JWT or 'Bearer <jwt>' format
- Update helper text to point to hardcover.app → Settings → API

* fix(hardcover): surface note-sync no-ops and harden book resolution

- Show toast feedback when book data is still loading, Hardcover is not configured,
  or the current book has no annotations/excerpts to sync
- Show an explicit info toast when note sync finds no new changes
- Parse Hardcover search results in the current hits/document response shape
- Resolve note sync through ensureBookInLibrary for parity with progress sync
- Add console logging for note/progress sync failures

* debug(hardcover): add runtime instrumentation for note sync

* feat(metadata): keep identifier stable and store ISBN separately

- Add dedicated metadata.isbn field
- Expose ISBN as its own editable field in book metadata
- Preserve identifier semantics for existing source IDs and hashes
- Route metadata auto-retrieval ISBN handling through the new field
- Prefer metadata.isbn for Hardcover matching

* fix(hardcover): avoid wasm sqlite for note mappings on web

- Store Hardcover note sync mappings in localStorage on web
- Keep sqlite-backed mappings for desktop/native environments
- Remove the web-only database dependency from manual note sync

* fix(hardcover): dedupe notes by payload hash across unstable note IDs

- Add payload-hash lookup in HardcoverSyncMapStore
- Reuse existing journal mapping when payload already synced
- Prevent duplicate insertions when note IDs change or duplicate locally

* fix(hardcover): avoid duplicate quote export when annotation note exists

- Detect excerpt+annotation pairs for the same highlight
- Skip standalone excerpt export when annotation has note text
- Keep annotation export as the single source of truth

* docs(hardcover): add consolidated change summary for review

* fix(hardcover): suppress excerpt export by CFI when annotation note exists

* fix(hardcover): suppress empty-note annotation duplicates when note exists

* fix(hardcover): deduplicate notes by text and cfi base node

* refactor(hardcover): optimize sync performance, add rate limiting and clean up debug tools

* chore: remove dev-only change log from main

* test(hardcover): add unit tests for sync mapping and client logic

* chore: custom deployment and UI fixes

* fix(hardcover): use timestamptz for accurate annotation time

* fix(hardcover): use date scalar and RFC 3339 formatting for journal entries

* Revert "chore: custom deployment and UI fixes"

This reverts commit 0329aba7129d1e1ebf2c663804b8fba9a9f87b91.

* Fix hardcover progress dates and surface imported ISBNs

* Fix Hardcover currently reading sync

* fix(hardcover): avoid promoting note sync status

* style(hardcover): apply prettier formatting

* test(hardcover): fix strict TypeScript assertions

* test(hardcover): harden sync regression coverage

* test(hardcover): fix lint and formatting regressions

* fix(hardcover): narrow note dedupe range matching

* refactor(hardcover): extract note dedupe helpers

* refactor(isbn): extract metadata normalization helpers

* feat(hardcover): improve synced quote formatting
2026-04-03 09:06:43 +02:00
Mohammed Efaz 888f4afde9 fix: preserve paragraph mode reading layouts and other UI/UX fixes (#3730)
* fix: paragraph mode

* test: paragraph mode

* test: remove paragraph mode

* fix: paragraph utils

* fix: paragraph hook

* fix: paragraph overlay

* fix: paragraph bar

* fix: paragraph control

* fix: paragraph shortcuts

* test: paragraph utils

* test: paragraph hook

* test: paragraph overlay

* test: paragraph shortcuts

* fix: paragraph overlay

* test: paragraph mode

* test: shortcuts

* test: remove overlay

* test: remove hook

* test: remove utils

* fix: paragraph overlay

* fix: paragraph overlay

* feat: paragraph overlay

* fix: vertical container sizing

* test: paragraph container

* fix: paragraph animation

* fix: paragraph text animation

* fix: remove container morph
2026-04-02 20:56:38 +02:00
Huang Xin 05afaab5fd fix(layout): fixed static image size and layout shift on window resize, closes #3634 (#3729) 2026-04-02 20:50:02 +02:00
Huang Xin ff962a1f02 fix(android): auto-shutdown native TTS engine after 30 min idle to save battery (#3728)
When the Android native TTS engine is paused or stopped but not shut down,
it holds resources and drains battery. This adds a 30-minute idle timer that
automatically shuts down the TextToSpeech engine and MediaPlaybackService
after inactivity. The engine transparently re-initializes on next use.

Also adds missing androidx.lifecycle:lifecycle-process dependency to fix
ProcessLifecycleOwner build error.

Closes #3713

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:00:21 +02:00
Huang Xin 62df631dd1 feat(theme): add atmosphere easter egg with video overlay and ambient audio (#3727)
Hidden easter egg: re-clicking the active light mode sun icon
or dark mode moon icon activates an ambient atmosphere with a
komorebi leaf shadow video overlay and forest background audio. Audio
adapts to theme: birds for light mode, crickets for dark mode.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:12:10 +02:00
Lex Moulton c9647276b1 feat(rsvp): progress bar per chapter, speed selector dropdown, and UX improvements (#3723)
* fix(rsvp): rename pause setting to punctuation delay for clarity

* fix(rsvp): update chapter header as user crosses TOC sections

* fix(rsvp): stop playback at end of book instead of restarting last chapter

* feat(rsvp): convert WPM badge to speed selector dropdown

* feat(rsvp): scroll active chapter to center when chapter dropdown opens

* fix(rsvp): show correct chapter name in header instead of "Select Chapter"

* fix(rsvp): start from selected chapter when switching via dropdown

* fix(rsvp): restore saved position when resuming from a different section

* fix(rsvp): remove shrink animation from header buttons on click

* refactor(rsvp): process one spine section at a time, greadtly reducing complexity

* refactor(rsvp): remove dead state and derive progress from currentIndex

* feat(rsvp): allow pausing during countdown

* fix(rsvp): use relocate event instead of fixed 500ms delay for chapter transitions

* fix(rsvp): persist WPM and punctuation pause settings across sessions

* fix(rsvp): prefix unused bookKey field with underscore to satisfy lint

* Revert "fix(rsvp): prefix unused bookKey field with underscore to satisfy lint"

This reverts commit 7b3a34813f0c3771e9af8d00c7c7dc77c8db161c.

* fix(rsvp): remove unused bookKey field from RSVPController

* feat(rsvp): make progress bar draggable

* fix: revert settings.json changes

* fix(rsvp): restore genuinely useful comments

* i18n: update translations

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-04-02 03:31:58 +02:00
Mohammed Efaz 9ecb9b24d2 feat: make reading ruler selection and step navigation coherent (#3722)
* refactor(reader): extract reading ruler math helpers

* fix(reader): keep text selectable inside reading ruler

* feat(reader): route taps to ruler step navigation

* feat(reader): route keyboard navigation to ruler steps

* fix(reader): animate ruler mask and frame together

* fix(reader): preserve drag anchor for ruler handles

* fix(reader): fall back to page turns at ruler edges
2026-04-01 18:59:44 +02:00
Huang Xin f0ab05bbde chore(agent): update agent skills and memories (#3721) 2026-04-01 16:44:52 +02:00
Huang Xin f1a08565e3 fix(storage): paginate stats query and align file size formatting (#3720)
Paginate Supabase select queries in the storage stats API to avoid
the 1000 row default limit. Align StorageManager's formatFileSize
with useQuotaStats calculation so quota values display consistently.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:44:15 +02:00
Huang Xin b8ddb5475e feat(sync): add full sync option for annotations in koplugin, closes #3710 (#3718)
Add "Full sync all annotations" menu item that pushes and pulls all
annotations regardless of the last sync timestamp, enabling users to
sync old highlights that were created before the plugin was installed.

Changes:
- Add full_sync parameter to push/pull that bypasses timestamp filter
  and uses since=0 for pulling all server annotations
- Deduplicate by annotation ID alongside position-based dedup
- Store server ID on pulled annotations and reuse it when pushing
- Parse ISO 8601 timestamps from server to preserve original
  created/updated dates instead of using current time
- Resolve KOReader page numbers from xpointers via getPageFromXPointer
- Resolve Readest page numbers from CFI via getCFIProgress on pull

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 15:35:48 +02:00
Huang Xin 74401fc1bb fix(library): always sort series books by index ascending, closes #3709 (#3717)
* fix(library): always sort series books by index ascending, closes #3709

When grouping by series, the sort direction (asc/desc) was applied to
within-series book sorting, causing books to appear in reverse series
index order when the library was sorted descending. Now series index
sort is always ascending (1, 2, 3…) regardless of the global sort
direction. Also sort series groups by name when "Sort by Series" is
selected instead of falling back to updatedAt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(library): skip merge sort when inside a series group

The allItems.sort at the end of sortedBookshelfItems was re-sorting
books using the regular bookSorter (e.g. Date Read), which overrode
the within-group sort that correctly prioritized series index. Now
when inside a group, the already-sorted books are returned directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:01:48 +02:00
Huang Xin 29df8522fa chore(bump): bump Tauri to the latest version (#3716) 2026-04-01 10:06:23 +02:00
Teodor-Mihai Cosma 9f958a44e2 feat(i18n): add Romanian (ro) translation (#3708)
* feat(i18n): add Romanian (ro) translation

* chore: update tauri submodule for Romanian language support
2026-04-01 09:22:04 +02:00
Huang Xin 0e516f6e56 chore(test): add unit tests and enforce dash-case naming for test files (#3715)
Add ~290 new unit tests covering utils (lru, diff, css, a11y, walk,
usage, txt-worker), services (EdgeTTSClient, transformers), and
suppress noisy console output across all test files. Rename 27
camelCase test files to dash-case for consistency.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 09:14:00 +02:00
Huang Xin b71b246601 feat(settings): add TTS settings tab and highlight opacity, closes #3661 (#3712)
Add a new TTS tab in settings with media metadata update frequency control
(sentence/paragraph/chapter) to reduce Bluetooth notification spam, and move
TTS highlight settings from Color tab to the new TTS tab. Also add a highlight
opacity setting with live preview in the Color tab.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 06:35:26 +02:00
Huang Xin 94843902ac fix(annotations): fix all annotations grouped under last chapter for fragment-href TOCs, closes #3688 (#3706)
When TOC entries use fragment-suffixed hrefs (e.g. ch01.xhtml#ch01),
the sectionsMap lookup matched subitems with cfi: undefined instead of
parent sections with valid CFIs. This caused findTocItemBS to map every
annotation to the last TOC entry. Now skip subitems lacking a CFI and
fall back to the base section.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 17:56:23 +02:00
Huang Xin f67930feb1 fix(opds): fix Copyparty books showing as "Untitled" in mixed feeds, closes #3667 (#3705) 2026-03-31 17:35:14 +02:00
Huang Xin 5e048ddab1 fix(iOS): use correct system theme mode in auto mode on iOS, closes #3698 (#3704) 2026-03-31 17:06:08 +02:00
Huang Xin e68dedd10d fix(layout): fix primary view detection on fractional DPR devices, closes #3681 (#3701) 2026-03-31 15:04:02 +02:00
Huang Xin d22b8bec1e i18n: update translations for aria label (#3697) 2026-03-30 19:10:31 +02:00
Huang Xin e9c5ebb696 fix(fonts): fix Adobe font deobfuscation and CSS var fallbacks, closes #3662 (#3696)
Two issues caused embedded EPUB fonts to fail:

1. Adobe font deobfuscation (http://ns.adobe.com/pdf/enc#RC) derived the
   XOR key from the wrong UUID. getUUID() picked the first UUID across all
   dc:identifier elements (e.g. Calibre's internal UUID) instead of the
   book's unique-identifier. Also fixed getElementById not working on
   DOMParser-parsed XML (no DTD), and made UUID regex case-insensitive.

2. transformStylesheet replaced generic font families (sans-serif, serif,
   monospace) with CSS var() references without fallback values. In
   fixed-layout iframes where setStyles doesn't inject the variables,
   the undefined var() invalidated the entire font-family declaration
   per CSS spec, causing all fonts to fall back to system defaults.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:06:22 +02:00
Huang Xin 956c71cd7b chore: migrate from ESLint to Biome for linting (#3694)
Replace ESLint with Biome for ~14x faster linting (~360ms vs ~5s).

- Add biome.json with rules matching ESLint parity (Next.js, a11y,
  TypeScript, unused vars/imports)
- Remove eslint, @typescript-eslint/*, eslint-config-next,
  eslint-plugin-jsx-a11y, @eslint/* from deps
- Remove eslint.config.mjs
- Update lint script to: tsgo --noEmit && biome check .
- Fix 11 real code issues caught by Biome (banned types, explicit any,
  unsafe finally, unreachable code, shadowed names)
- Disable Biome formatter (Prettier stays for Tailwind class sorting)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 16:25:04 +02:00
Huang Xin b4207bd742 chore(deps): bump vulnerable dependencies to address Dependabot alerts (#3693) 2026-03-30 15:59:03 +02:00
Huang Xin ec26ef4f29 fix(shortcuts): change bookmark shortcut from Ctrl+D to Ctrl+B (#3691)
* fix(shortcuts): change bookmark shortcut from Ctrl+D to Ctrl+B, closes #3675

Ctrl+D was bound to both Toggle Bookmark (General) and Dictionary
Lookup (Selection). When text was selected and Ctrl+D pressed, both
actions fired — opening the dictionary AND adding an unwanted bookmark.

Changed bookmark to Ctrl+B/Cmd+B to resolve the conflict. Added a
unit test that detects identical keybinding lists across actions to
prevent this class of bug in the future.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* i18n: mark shortcut section names for translation

Wrap SHORTCUT_SECTIONS values with stubTranslation() so i18next-scanner
picks them up. Translate the 4 new keys (General, Text to Speech, Zoom,
Window) across all 29 locales.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:35:40 +02:00
Huang Xin b872868136 fix(layout): fixed infinite expand calls and freeze in the paginator, closes #3683 (#3692) 2026-03-30 15:16:56 +02:00
Huang Xin 797fe9c604 fix(layout): fixed infinite expand calls and freeze in the paginator, closes #3683 (#3690) 2026-03-30 14:50:59 +02:00
Huang Xin 8ed9290659 layout: don't truncate remaining progress info without status info, closes #3678 (#3685) 2026-03-30 05:52:09 +02:00
Huang Xin 8e6451863f css: add css selector for status badge, closes #3678 (#3684) 2026-03-30 05:19:29 +02:00
Huang Xin c688612888 chore(fdroid): build qcms wasm for fdroid (#3680) 2026-03-29 20:08:08 +02:00
Huang Xin b3333c384c chore(fdroid): get rid of wasm binaries in fdroid build (#3677) 2026-03-29 18:31:46 +02:00
Huang Xin 84349ab12d chore(release): exclude turso wasm in app builds (#3674) 2026-03-29 06:35:39 +02:00
Huang Xin c4e3315642 feat(scroll): add single section scroll option, closes #3663 (#3668) 2026-03-28 13:57:20 +08:00
Huang Xin bbfc82e50d feat(android): add foss flavor build without gms services (#3666) 2026-03-28 05:36:09 +01:00
Huang Xin 966f5e2acd fix(opds): fixed image download from ODPS server on the web, closes #3649 (#3658) 2026-03-27 13:21:52 +01:00
Huang Xin 45e5f0fa61 fix(eink): disable range editor loupe for annotations on Eink devices, closes #3655 (#3656) 2026-03-27 10:26:36 +01:00
Huang Xin 3d4d1482aa feat: add keyboard shortcuts help dialog (#3653)
Add a keyboard shortcuts help dialog toggled with '?' that displays all
shortcuts grouped by section with platform-appropriate key rendering.

Restructure DEFAULT_SHORTCUTS to include i18n descriptions and section
metadata. Translate 37 new keys across 29 locales.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:59:38 +08:00
Huang Xin 5f897f648f feat(tts): add shortcuts to navigate and play/pause in TTS mode, closes #3620 (#3651) 2026-03-27 06:39:17 +01:00
Huang Xin 26fec924fc chore: bump turso to the latest version (#3650) 2026-03-27 06:28:59 +01:00
Huang Xin af9cf33936 fix(android): never try to fight with the navigation bar on Android ever, closes #3618 (#3646) 2026-03-26 17:40:49 +01:00
Huang Xin 52df478f21 fix: show proper background images in continuous scrolled mode, closes #3638 (#3645) 2026-03-26 16:41:55 +01:00
Huang Xin 97555a7e88 chore: bump next.js, opennextjs and wrangler to the latest versions (#3642) 2026-03-26 15:57:19 +01:00
Lee Kai Ze c7e82825f5 fix(koplugin): avoid resurrecting deleted annotations on pull (#3639)
Closes #3621.
2026-03-26 15:13:32 +01:00
dependabot[bot] bb82ab6c8a chore(deps): bump android-actions/setup-android (#3631) 2026-03-26 14:01:27 +08:00
Huang Xin e2faa9ad75 compat(android): disable native long-click on the WebView to prevent the system image context menu, closes #3629 (#3630) 2026-03-26 04:12:54 +01:00
Huang Xin f310305834 fix(library): mixed sorting for group and ungroupped books, closes #3596 (#3627) 2026-03-25 16:55:20 +01:00
Huang Xin 5a072e7d1f fix(pdf): apply theme colors for PDFs, closes #3593 (#3626) 2026-03-25 16:50:12 +01:00
Huang Xin 64675820f1 fix(koplugin): fixed koreader crash on logout, closes #3598 (#3603) 2026-03-23 15:08:51 +01:00
Huang Xin 1e942a23b4 chore(release): generate changelog from release notes for google play (#3591) 2026-03-22 16:38:26 +01:00
Huang Xin a92c357982 chore(release): disable linux-arm build for now as turso can't work on it for now (#3590) 2026-03-22 14:53:45 +01:00
Huang Xin 1ebf5e7b52 fix(release): skip architecture check for 32-bit ARM (#3589) 2026-03-22 14:22:22 +01:00
Huang Xin c11f79e843 release: version 0.10.1 (#3588) 2026-03-22 13:29:13 +01:00
Huang Xin 87f0240b0a compat(footnote): support footnote text in alt attribute of the image, closes #3576 (#3587)
refactor: remove unused continuous scroll
2026-03-22 12:17:02 +01:00
Huang Xin 2905506017 fix(layout): fixed total scrollable width in vertical scrolled mode, closes #3583 (#3586) 2026-03-22 11:56:12 +01:00
Huang Xin 1936136596 fix: resolve various tracked exceptions in ph (#3584)
* fix: handle synced bookmarks without cfi

* chore: clean up some exceptions in ph
2026-03-22 08:16:38 +01:00
Huang Xin e0cf7e8d9f fix: handle number input value clip in settings on mobile devices (#3582) 2026-03-22 05:26:21 +01:00
Huang Xin 0177a03a90 fix(tts): properly follow tts reading position in scrolled mode (#3581) 2026-03-21 18:08:45 +01:00
Huang Xin f5df80f154 feat(koplugin): support sync bookmarks between Koreader and Readest devices (#3580) 2026-03-21 17:58:38 +01:00
Huang Xin 76b239f382 feat(koplugin): add support for annotation sync (#3579)
Add bidirectional annotation/highlight sync between KOReader and Readest:

- Add xpointer0/xpointer1 fields to BookNote and DBBookNote types for
  KOReader XPointer positions alongside Readest's CFI format
- Extend transform layer to pass through xpointer fields to/from DB
- Convert CFI→XPointer on push and XPointer→CFI on pull in useNotesSync,
  discarding notes that fail conversion
- Support KOReader's text()[K].N indexed text node format in xcfi.ts for
  paragraphs with inline elements (e.g. <a> page anchors)
- Generate KOReader-compatible XPointers: text().N for single text nodes,
  text()[K].N only when multiple direct text nodes exist
- Skip cfi-inert elements (injected by Readest at runtime) in XPointer
  path building and resolution
- Map highlight colors between KOReader and Readest color systems
- Implement KOReader plugin annotation push/pull with deterministic IDs,
  auto-sync on document open/close, and UIManager refresh on pull
- Refactor koplugin into focused modules: syncauth, syncconfig,
  syncannotations, selfupdate

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:43:51 +01:00
Huang Xin 2f430bf2ff feat(koplugin): add self-update check and install from menu (#3575)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 08:16:50 +01:00
Huang Xin 0e8605d298 feat(reader): import Foliate annotations on book open (Linux only), closes #2180 (#3574)
* feat(reader): import Foliate annotations on book open (Linux only), closes #2180

Automatically imports annotations, bookmarks, and reading progress from
Foliate's data files when opening a book on Linux. Uses foliateImportedAt
flag to prevent re-importing on subsequent opens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(annotation): move Foliate import into annotation provider pattern

Restructure annotation import as a multi-provider service following the
translators pattern. Foliate becomes a provider under
services/annotation/providers/, making it easy to add more import sources.
Each provider controls its own availability check and skip-if-imported guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 05:04:46 +01:00
Huang Xin 7445d5befe feat(library): add batch refresh metadata option, closes #3294 (#3573)
Add a "Refresh Metadata" option under Advanced Settings that re-parses
book files to update metadata (series info, language, etc.) for books
imported before these fields were supported.

- Add refreshBookMetadata() in bookService that opens a book file,
  re-parses with DocumentLoader, and updates metadata/metaHash/series
  without touching updatedAt or user-edited fields
- Add menu item in SettingsMenu with progress display
- Add unit tests for single-book metadata refresh
- Translate new i18n strings across all 29 locales

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:32:09 +01:00
Huang Xin e41bcfbac9 fix(txt): fix chapter detection for bare numbered headings, closes #3570 (#3572)
Three bugs in createChapterRegexps for English txt-to-epub conversion:

1. numberPattern had a capturing group (\d+|...) that leaked single
   digits into split() results instead of chapter titles. Changed to
   non-capturing (?:\d+|...).

2. combinedPattern wrapped the heading in (?:...) so split() consumed
   the title without returning it. Changed to (...) capturing group,
   matching the Chinese regex structure.

3. The prefix (?:^|\n|\s) allowed matching Chapter/Section after any
   whitespace, causing mid-sentence false positives. Changed to
   (?:^|\n) for line-start only.

Added a second-tier regex for bare numbered headings (e.g. "1.1The
Elements of Programming", "1Building Abstractions") commonly found
in academic texts. Dotted numbers allow optional space before title;
single bare digits require immediate title to avoid footnote matches.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:00:33 +01:00
Huang Xin 91bc4ddec7 feat(library): backup to and restore from a zip file (#3571) 2026-03-20 18:27:52 +01:00
Huang Xin e8f70b896e chore: bump next.js from 16.1.6 to 16.1.7 (#3569) 2026-03-19 18:11:26 +01:00
Huang Xin 1f4f5f8a6d feat(annotator): responsive layout for the loupe (#3568) 2026-03-19 17:54:24 +01:00
Huang Xin 764acf59de chore(agent): add project memory (#3567) 2026-03-19 17:46:45 +01:00
Huang Xin eab83c6d3f feat(annotator): show the loupe when selecting text in instant annotation, closes #3539 (#3565) 2026-03-19 15:10:33 +01:00
dependabot[bot] 7f62cdcab9 chore(deps): bump pnpm/action-setup in the github-actions group (#3564) 2026-03-19 13:06:00 +08:00
Huang Xin e4ab06abcd fix(footnote): don't preload other sections in footnotes (#3563) 2026-03-19 04:10:16 +01:00
Huang Xin fef0aa6947 fix(perf): revert back next/image with lazying loading for much better perf (#3562) 2026-03-18 14:49:06 +01:00
Huang Xin 2935eacb1c fix(layout): fixed header background color on mobile devices (#3561) 2026-03-18 13:08:43 +01:00
Huang Xin ad9bb58cd4 fix(ios): resolve stale closure crash preventing highlight popup on iOS (#3559) 2026-03-18 10:11:13 +01:00
Huang Xin 871d6467c3 fix(layout): more responsive layout for the transfer queue (#3558) 2026-03-18 06:32:55 +01:00
Huang Xin 3f19ce24de chore(agent): add gstack skills (#3557) 2026-03-18 06:08:48 +01:00
Huang Xin 8280585e70 compat(css): fix table layout regression issue, closes #3551 (#3556) 2026-03-17 17:52:07 +01:00
Huang Xin 1f7483b911 feat: scroll to the nearest item in the search results or annotation lists (#3555) 2026-03-17 16:01:56 +01:00
Huang Xin b2bb92036b fix(ios): decode percent-encoded file URIs in copy_uri_to_path (#3553) 2026-03-17 13:17:42 +01:00
Huang Xin 3831f24ff7 fix(android): fix page navigation layer z-index, closes #3511 (#3552) 2026-03-17 09:52:21 +01:00
Huang Xin 3bec89c85d fix(progress): show remaining pages for current section instead of all loaded sections (#3550) 2026-03-17 09:18:39 +01:00
Huang Xin 3dfe6bd65e fix(layout): fix parallel read layout on smaller screens (#3549) 2026-03-17 07:34:55 +01:00
Huang Xin b00d321817 refactor(reader): extract shared panel drag hooks and add vertical drag to Notebook (#3548)
Extract useSwipeToDismiss and usePanelResize hooks from duplicated code
in SideBar and Notebook. Add mobile swipe-to-dismiss drag handle to
Notebook matching SideBar's existing behavior. Fix drag cursor showing
col-resize instead of row-resize during vertical drags.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 04:27:27 +01:00
Huang Xin 1af55e24da feat(epub): support continuous scroll and spread layout for EPUBs, closes #3419 and closes #1745 (#3546) 2026-03-16 18:24:07 +01:00
Huang Xin f7b2a2432c fix(export): apply block quote syntax to every line in annotation export, closes #3534 (#3536)
Add formatBlockQuote utility and blockquote nunjucks filter so both
default and custom template exports prefix every line with `>`.
Document all available formatters in the custom template help panel.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:23:17 +01:00
Huang Xin db3dee025b feat(booshelf): dedupe books with the same meta hash (#3535) 2026-03-14 15:14:22 +01:00
Huang Xin 25352efece chore: bump dependencies for Dependabot alerts (#3533) 2026-03-14 06:57:43 +01:00
Huang Xin 1297e33c62 doc(agent): add rules files that are automatically loaded into context alongside CLAUDE.md (#3532) 2026-03-14 04:37:41 +01:00
Huang Xin 8274c6bc4f feat(node): refactor appService into focused service modules and add app service for Node runtime (#3530)
This also closes #3431.
2026-03-13 17:51:35 +01:00
Huang Xin ed5bbd25d6 fix(opds): more accurate error message when downloading books, closes #2656 (#3529) 2026-03-13 08:26:54 +01:00
Huang Xin d06e1849cc feat(rsvp): add persistent context, display settings, and layout improvements, closes #3333 (#3528)
* feat(rsvp): add persistent context, display settings, and layout improvements, closes #3333

Add always-visible collapsible context panel, font size adjustment,
ORP color selection, and stable context window that only rebuilds on
scroll. Refactor speed controls into playback row with collapsible
settings behind a gear icon. Translate new i18n keys across 29 locales.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(selfhost): update docker db schema to match FileRecords (#3527)

In #2636, FileRecord was defined to have updated_at  field
which is used when it is accessed from the database. But the
local dev setup is missing this field.

This diff adds an updated_at column to match the expectation

* chore(ci): cache system dependency and rustc outputs in ci

* chore(ci): lint script changed from tsc to tsgo

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Azeem Bande-Ali <me@azeemba.com>
2026-03-13 06:57:47 +01:00
Azeem Bande-Ali 34ad6e6749 fix(selfhost): update docker db schema to match FileRecords (#3527)
In #2636, FileRecord was defined to have updated_at  field
which is used when it is accessed from the database. But the
local dev setup is missing this field.

This diff adds an updated_at column to match the expectation
2026-03-13 05:15:55 +01:00
Huang Xin b163012488 fix(link): prevent opening duplicate browser tabs on Tauri, closes #3514 (#3525) 2026-03-12 17:29:04 +01:00
Huang Xin f9a3559086 fix(library): improve sorting and grouping interaction, closes #3517 (#3524)
- Sort author groups by last name instead of first name when sorting by author
- Sort series groups by book author instead of series name when sorting by author
- Place ungrouped books before custom groups instead of mixing them together

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:59:50 +01:00
Huang Xin 674a0bf16d compat(footnote): support more footnote selectors, closes #3515 (#3523) 2026-03-12 16:46:57 +01:00
Huang Xin 9b53ccc9de fix(i18n): handle POSIX locale values in getLocale(), closes #3518 (#3522)
When LANG=C.UTF-8, navigator.language can return 'C' which is not a
valid BCP 47 tag, causing Intl.NumberFormat and toLocaleString to throw.
Normalize POSIX values (C, C.UTF-8, POSIX) to 'en-US' at the source.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:36:48 +01:00
Huang Xin 7a605a357a feat(pdf): support pitch to zoom and scroll mode for PDFs, closes #3461 (#3520) 2026-03-12 16:07:55 +01:00
Huang Xin af649edd0d fix(pdf): show search results when navigating to new page, closes #3148 (#3513) 2026-03-11 17:55:58 +01:00
Huang Xin 64a71e25e4 fix(layout): make horizontal scroll bar visible in fixed-layout EPUB, closes #3506 (#3512)
And fix some text not shown in fixed-layout EPUB.
2026-03-11 15:03:05 +01:00
Huang Xin 51a3767940 feat(a11y): show prev/next section buttons for screen reader, closes #3290 (#3511) 2026-03-11 13:33:36 +01:00
Huang Xin a8572ab7c6 feat(reader): tap notch area to scroll to top in scrolled mode, closes #3474 (#3510) 2026-03-11 18:20:38 +08:00
Huang Xin 907b672313 fix(a11y): improve TOC screen reader accessibility for NVDA, closes #3477 (#3509) 2026-03-11 14:30:01 +08:00
Huang Xin 8df9f909b4 fix(reader): add Always on Top toggle to reader view, closes #3482 (#3505)
- Apply alwaysOnTop setting on reader window init so books opened
  in a new window correctly inherit the setting
- Update tauriHandleSetAlwaysOnTop to apply to all open windows
  so toggling from any window keeps all windows in sync

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 13:15:08 +01:00
Huang Xin bcd7a90f27 fix(layout): add top/bottom margin to container in scrolled mode, closes #3463 (#3504)
* fix(layout): add top/bottom margin to container in scrolled mode, closes #3463

When showMarginsOnScroll is enabled, the paginator margins are set to 0
but the FoliateViewer container had no compensating padding, causing
header/footer bars to overlap content. Now the container padding aligns
content top to the bottom of the header bar (gridInsets.top + 44px) and
content bottom to the top of the footer bar (52px + safe area padding).
Also fixes the footer bar height constant from 44 to 52 to match
ProgressBar's actual h-[52px].

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(ci): cache all crates including local path deps in Tauri build

Add cache-all-crates: 'true' to Swatinem/rust-cache so that vendored
local path dependencies (packages/tauri/crates/, packages/tauri-plugins/)
are cached between CI runs instead of being recompiled from scratch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 10:40:03 +01:00
Huang Xin 5646e0cfb5 fix(txt): add stream() to RemoteFile to fix large TXT import on desktop, closes #3495 (#3502)
RemoteFile (used on all desktop platforms) extended File([]) with empty
data and overrode slice(), text(), arrayBuffer() but not stream(). The
large file path (>8MB) introduced in #3320 uses file.stream() to read
content incrementally, which returned empty data from the base File
class, causing "No chapters detected" for large TXT files.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:00:44 +01:00
Huang Xin fad27d74a0 compat(android): show button navigation bar on Android, closes #3466 (#3501) 2026-03-09 17:36:13 +01:00
Huang Xin 5fbbfa523b chore(ci): fix rust cache (#3500) 2026-03-09 15:32:01 +01:00
Huang Xin 569c6707a4 fix(macOS): fix traffic light visibility in sidebar, closes #3488 (#3499) 2026-03-09 15:10:13 +01:00
Huang Xin 99f8a29326 fix(css): apply Line Spacing to list elements, closes #3494 (#3498) 2026-03-09 14:01:44 +01:00
Huang Xin 04737d6f35 fix(layout): update safe insets in reader page, closes #3469 (#3497) 2026-03-09 13:54:03 +01:00
Huang Xin 8850e6c00f feat(pdf): support TTS and annotation on PDFs, closes #2149 & #3462 (#3493)
* chore: bump jsdom to the latest version

* feat(pdf): support TTS and annotation on PDFs, closes #2149 & closes #3462
2026-03-09 10:28:19 +01:00
Huang Xin 93b96d64eb fix(sidebar): use position fixed and transform for mobile sidebar (#3490)
* chore: bump nodejs version to 24

* fix(sidebar): use position fixed and transform for mobile sidebar

Use position: fixed to prevent horizontal scrolling on the mobile
bottom sheet, and replace style.top with transform: translateY() for
smooth drag performance. Cache element refs to avoid
document.querySelector on every drag frame. Apply the same position:
fixed fix to the notebook panel. Closes #3492

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:04:37 +01:00
srsng 9f8894c1e0 feat(setting): add an option to hide Scrollbar in scroll mode, closes #3480
* feat(setting) impl settings option: hide Scrollbar of scroll mode

* refactor(setting): disable hide scrollbar in paginated mode, add i18n translations

- Add disabled prop to Hide Scrollbar toggle when not in scroll mode
- Remove unnecessary `as const` assertion on string literal
- Add "Hide Scrollbar" translations for all 28 locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 05:21:58 +01:00
Huang Xin dac4f2e8ec chore: experimental vinext build (#3486) 2026-03-06 18:04:28 +01:00
Huang Xin 54bc1514df feat(database): add platform-agnostic schema migration system (#3485) 2026-03-06 20:07:26 +08:00
Huang Xin 97cab2d70b feat(database): support turso fts in tauri apps (#3484) 2026-03-05 21:00:15 +01:00
Huang Xin 13588b4a65 chore(testing): add Tauri integration tests and E2E test infrastructure (#3483)
Set up WebDriver-based testing for the Tauri app with two tiers:
- Vitest browser-mode tests (*.tauri.test.ts) running inside the Tauri WebView
  for plugin IPC testing (libsql, smoke tests)
- WDIO E2E tests (*.e2e.ts) for UI-level interaction testing

Key changes:
- Add webdriver Cargo feature gating tauri-plugin-webdriver
- Add runtime capability for remote URLs (webdriver builds only)
- Add vitest.tauri.config.mts and wdio.conf.ts connecting to embedded
  WebDriver server on port 4445
- Add shared tauri-invoke helper for IPC from Vitest iframe context
- Add testing documentation in docs/testing.md
2026-03-05 19:14:01 +01:00
Huang Xin 0f5bd5ca1c fix(footnote): add overflow-wrap to footnote popup to prevent long words from overflowing (#3479)
The change adds overflow-wrap: break-word to the footnote popup body styles, which ensures long unbreakable strings (like URLs or long words) wrap properly instead of overflowing
the popup container.
2026-03-05 10:49:28 +01:00
Huang Xin a74c1a56a9 fix(metadata): parse series info from epub only when book series info not available (#3478) 2026-03-05 09:53:28 +01:00
Huang Xin 1e9bd1d821 chore(database): unit testing and feature detect for fts and vector search (#3476) 2026-03-05 07:41:16 +01:00
Huang Xin 02cc0a9ebb chore: bump turso to 0.5.0 (#3475) 2026-03-04 19:54:58 +01:00
Huang Xin 5273ef75dc feat(database): add database service abstraction with libsql/turso backend (#3472) 2026-03-05 02:38:23 +08:00
Blyrium bd957a4eb8 i18n: added <0> and <1> tags for SL (#3460) 2026-03-04 03:06:00 +01:00
scinac 38552a0c2e feat(reader): adding current Time and Battery to Footer (#3306) (#3402)
* added current time to desktop bar

* added time prototype to footer, needs code cleanup and settings toggle

* fixed settings toggle, added translations and code cleanup

* added battery support and moved Statusbar to own Component

* #3306 added 24 hour clock support

* refactored code styling and getting rid of any type in battery hook

* Add battery info for Tauri Apps

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-03-03 17:10:13 +01:00
Huang Xin 0609e828b1 fix(css): unset hardcoded calibre color and background color, closes #3448 (#3457) 2026-03-03 11:06:03 +01:00
Huang Xin 35ade2c855 fix(tts): handle documents without lang attribute or XHTML namespace, closes #3291 (#3456) 2026-03-03 10:35:33 +01:00
Huang Xin b68c14da1f i18n: add translations for Slovenian(sl), closes #3453 (#3455) 2026-03-03 07:20:59 +01:00
Huang Xin 5c41394961 feat(footnote): make popup window size more responsive for longer footnotes, closes #3425 (#3454) 2026-03-03 07:09:34 +01:00
Huang Xin 5685944599 fix(css): unset padding and margin in body, closes #3441 (#3452) 2026-03-03 04:52:21 +01:00
Huang Xin 94e761f681 fix(txt): more robust chapter extractor for TXT (#3446) 2026-03-02 18:20:50 +01:00
Huang Xin 7f636a2072 fix(toc): correct TOC grouping to prevent unnecessary nested layers (#3445) 2026-03-02 16:44:02 +01:00
Huang Xin 480b8b98a3 fix(css): properly constrain the max width and height of images, closes #3432 (#3444) 2026-03-02 16:20:01 +01:00
Huang Xin d1fb67316f compat(css): support duokan-page-fullscreen in spine to display cover image in fullscreen, closes #3424 (#3443) 2026-03-02 15:16:04 +01:00
Huang Xin f0e9ddd2ae feat(font): support loading custom font if embedded fonts in EPUBs are missing (#3439) 2026-03-02 09:18:18 +01:00
IGCFck b16a4445ae fix(opds): handle non-ASCII login details (#3436) 2026-03-02 07:01:47 +08:00
StepanSad 515d47e64d Update translation.json (#3423)
* Update translation.json

* Update translation for pages left in chapter

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-03-01 17:10:07 +01:00
Huang Xin 3fd78c4ed8 fix(gallery): support displaying svg image in image gallery mode, closes #3427 (#3435) 2026-03-01 17:08:51 +01:00
bfcs 152a95941a fix(translation): handle missing Cloudflare context on non-Cloudflare deployments (e.g., Vercel) (#3433)
* fix(translation): handle missing Cloudflare context on non-Cloudflare deployments (e.g., Vercel)

* Simplify error handling for Cloudflare context

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-03-01 16:40:45 +01:00
Huang Xin bf5805910d feat(footnote): add back navigation for footnote popup with link history, closes #3420 (#3434) 2026-03-01 16:30:59 +01:00
Huang Xin 431d14f4a4 fix(layout): respect grid insets for the zoom controller, closes #3426 (#3430) 2026-03-01 09:58:54 +01:00
Huang Xin 0d2e5b7c76 fix(translation): reduce initial layout shift in the translation view, closes #3078 (#3428)
* fix(css): allow overriding the padding of the root html

* fix(translation): reduce initial layout shift in the translation view, closes #3078
2026-03-01 09:12:02 +01:00
bfcs e949476d27 fix(translation): resolve DeepL translation failure with auto-detection (#3412)
* fix(translation): correctly handle DeepL source_lang 'AUTO' by omitting it

* refactor: backward compatibility

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-03-01 06:03:52 +01:00
Huang Xin 0afff573a1 chore: bump dependencies to resolve Dependabot alerts (#3421) 2026-02-28 18:31:33 +01:00
Huang Xin d4bb61f12b fix(layout): responsive layout for OPDS catalogs and download button (#3418) 2026-02-28 17:07:20 +01:00
Huang Xin 09c45b4615 fix(linux): avoid transitions API on WebKitGTK on Linux (#3417) 2026-02-28 16:35:39 +01:00
Huang Xin d8eef87bf0 chore(agents): add AGENTS.md for readest-app (#3415) 2026-02-28 15:30:31 +01:00
Huang Xin 66d2fdf999 release: version 0.9.101 (#3410) 2026-02-28 09:50:23 +01:00
Huang Xin d8e0ceeff1 fix(annotator): add page number in highlight export to Readwise (#3409) 2026-02-28 09:45:09 +01:00
Huang Xin f3ad97b989 fix(opds): add missing book description in OPDS feed (#3408) 2026-02-28 09:30:56 +01:00
Huang Xin 1bb49ab023 fix(tts): dispose of the TTS view when shutting down the TTS controller, closes #3400 (#3406) 2026-02-28 08:58:02 +01:00
bfcs f9a0b39586 fix: respect fixed translation quota in UI stats and DeepL provider (#3404) 2026-02-28 08:10:31 +01:00
Huang Xin c533da498d feat(annotator): add page number for annotations, closes #3082 (#3405)
* feat(annotator): add page number in annotation

* feat: add page number for annotations, closes #3082
2026-02-28 08:08:56 +01:00
Huang Xin b50bc0b854 fix: make touchpad scrolling respect the system’s natural scrolling settings, closes #3127 (#3398) 2026-02-27 07:24:49 +01:00
Huang Xin 96c465931c fix(toc): fix phantom subchapter TOC item (#3397) 2026-02-27 07:23:12 +01:00
Huang Xin 2bd54ac236 fix(tts): also show highlight when navigating in paused mode and improve abbreviations processing (#3396)
Closes #3317.
2026-02-27 06:46:27 +01:00
Huang Xin 6ad549d13c fix(iOS): correct sidebar insets on iPad and resolve occasional stale safe area inset on iOS (#3395) 2026-02-27 05:43:45 +01:00
Blyrium 67249370c9 fix(font): fix generic font family keywords bypassing user font settings (#3394)
* Fix generic font families resolving incorrectly

Replace `serif`, `sans-serif`, and `monospace` keywords in epub stylesheets with their corresponding CSS variables (`var(--serif)`, `var(--sans-serif)`, `var(--monospace)`), ensuring the user's configured fonts are always used.
Fixes https://github.com/readest/readest/issues/3334

* Got rid of the lookbehind

But now we're using a placeholder.
2026-02-27 08:55:24 +08:00
Huang Xin fe3ab011ca fix(tts): set document lang attribute when missing or invalid for TTS, closes #3291 (#3393) 2026-02-26 17:17:51 +01:00
Huang Xin 6cb4278b98 fix: fixed all progress at the last page of the book, closes #3383 (#3391) 2026-02-26 14:01:42 +01:00
Huang Xin 51468862a2 fix(ui): show progress 100% at the last page, closes #3383 (#3390) 2026-02-26 11:08:21 +01:00
Huang Xin b3a44d066f fix(layout): enlarge hit area for slider input on iOS, closes #3382 (#3389) 2026-02-26 09:26:28 +01:00
Huang Xin 68d4538d40 fix(layout): float the annotation navigation bar, closes #3386 (#3387) 2026-02-26 06:56:29 +01:00
Roy Zhu 80105af839 fix(txt): stabilize iOS large TXT import and decode picker paths (#3320)
* fix: add missing TXT worker files for large import path

* fix(ios): decode import paths and stabilize large TXT conversion

* style(txt): run prettier on TXT conversion files

* fix(txt): restore chunk iterator API and stream cancel behavior

* fix(txt): avoid unused private segment iterator

* chore: clean up log for unit tests

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-02-26 05:30:13 +01:00
Huang Xin 3904c1e8e7 perf: use GPU-accelerated scroll for smoother paging animation (#3385) 2026-02-26 03:39:37 +01:00
Alan 99be6c58e2 fix: close searchbar when adding a new annotation (#3384) 2026-02-26 09:20:27 +08:00
Huang Xin 664cc772d0 fix: more sensitive paging without snapping animation, closes #3310 (#3381) 2026-02-25 17:47:55 +01:00
Huang Xin 21208adbcf compat: add target class to hide import icon in the bookshelf, closes #3376 (#3380) 2026-02-25 14:13:10 +01:00
Huang Xin 70eb59e2d6 compat(css): only override img background when overriding book color, closes #3377 (#3379) 2026-02-25 11:43:02 +01:00
Huang Xin 3e7b57282e fix: delay context menu to prevent broken input loop on macOS, closes #3324 (#3378)
When a native context menu is triggered via right-click, the menu.popup()
call immediately takes control and disrupts the browser's pointer event
flow. This prevents the pointerUp event from being delivered, leaving the
input event loop in an inconsistent state where the first tap after
dismissing the menu is not captured.

The fix adds a 100ms delay before showing the context menu, allowing the
browser's input loop to complete the pointerUp event for the right-click
before the native menu interferes.
2026-02-25 11:22:25 +01:00
Huang Xin 534582b125 compat(css): unset none user-select in some EPUBs, closes #3370 (#3374) 2026-02-25 07:10:06 +01:00
Huang Xin 4465e6986e chore: add husky pre-commit and pre-push hooks (#3372) 2026-02-25 06:39:11 +01:00
Blyrium a535f6419e fix: allow CSS targeting of the "NUMBER pages left in chapter" label via <Trans> component (#3368)
* Allow users to change the "remaining pages" label

Makes the remaining page number and the label text that comes with it targetable with CSS.
Solves https://github.com/readest/readest/issues/3343.

* Fixed formatting
2026-02-25 06:11:45 +01:00
Huang Xin 65da9c1d47 compat(webview): compat with older webview for iterating gamepads (#3366) 2026-02-24 16:59:52 +01:00
Huang Xin 5f71fd9e47 fix(css): override inline image background color only when overriding book color, closes #3316 (#3365) 2026-02-24 16:04:28 +01:00
Huang Xin dcf75e07d1 feat(translator): add Khmer in translator target languages, closes #3323 (#3364) 2026-02-24 15:51:50 +01:00
Huang Xin 79ba9b3818 compat(css): unset font-family for body when set to serif or sans-serif, closes #3334 (#3363) 2026-02-24 15:18:12 +01:00
Huang Xin 128b238bcb feat: add directional view transitions with scroll preservation in library view, closes #3357 (#3362) 2026-02-24 14:56:45 +01:00
Mohammed Efaz e26f7e6a2c fix: empty paragraphs not skipped in paragraph mode (#3361)
* fix(paragraph): skip empty paragraph ranges

* test(paragraph): cover empty paragraph filtering
2026-02-24 09:05:35 +01:00
Huang Xin 4c5ff59bcf fix(layout): also scale table with parent width, closes #3284 (#3359) 2026-02-24 08:11:45 +01:00
Huang Xin 99b2a34bd2 compat(layout): fix insane block display for tables, closes #3351 (#3358) 2026-02-24 07:26:03 +01:00
Huang Xin 40f3268ef3 fix(layout): consistent padding and radius for the dialog header, closes #3352 (#3356) 2026-02-24 06:55:47 +01:00
Huang Xin 4dac0850c5 fix: add classes for progress info labels, closes #3343 (#3353) 2026-02-24 05:24:01 +01:00
Huang Xin 118538ba35 fix(epub): replace background also for scrolled mode, closes #3344 (#3350) 2026-02-24 04:37:44 +01:00
JustADeer 4a92cacd84 fix: changed tagName comparision to localName for case-insensitive in iframeEventHandlers (XHTML xmlns bug fix) (#3349) 2026-02-24 09:21:03 +08:00
Matt Vogel ce53cd2b47 feat: Readwise highlights sync (#3311) 2026-02-24 00:08:59 +08:00
JustADeer b99c1bc19a feat(ui): image viewing mode support (#3328)
* feat(ui): image viewing mode support

* Revert foliate-js submodule pointer to 72fda6a (CI-compatible)

* Fix long-press image viewing in foliateViewer instead of foliate-js and other refactors

* feat: add images navigation buttons and table viewer

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-02-22 17:28:48 +01:00
Aniket Kotal eec2c39f19 feat(docker/podman): self-hosting with docker/podman compose (#3312)
* initial files

* added testing files

* removed unused files

* cleaned additional mounts

* fixed sql init

* removed more unused files

* moved to docker folder

* revert package.json

* gitignore update

* env example comments and compose necessary healthcheck

* ghcr package impl

* updated dockerfile steps  for layer caching

* added development-stage to dockerfile to dev environment

* added documentation on how to use dockerfile and compose.yml

* fixed prettier issues

* fixed image tag

* removed workflow for later
2026-02-18 14:28:10 +01:00
Mohammed Efaz c6ae85484e fix(reader): clamp reading ruler within viewport (#3314) 2026-02-18 14:13:06 +08:00
Huang Xin 7a9f46e93c fix(layout): container layout for dimmed area of reading ruler, closes #3304 (#3313) 2026-02-17 18:34:48 +01:00
Mohammed Efaz b9f6578127 feat: remaining time in TTS mode (#3300)
* feat: add test

* chore: update test

* feat: add translations

* feat: add tts time

* feat: add tts time components

* feat: update test

* feat: fixes and update ui components

* refactor: revert translations and ui
2026-02-14 17:42:37 +01:00
Huang Xin e75a3d254e fix(tts): fixed an issue where starting TTS from the annotation tool did not work, closes #3292 (#3303) 2026-02-14 17:22:46 +01:00
Huang Xin ea15906acf fix(txt): fixed TXT import on platforms that CompressionStream is not working, closes #3255 (#3302) 2026-02-14 23:30:38 +08:00
Mohammed Efaz 15d2784725 fix: highlight in dark mode eink (#3299)
* fix: highlight in dark mode eink

* refactor: deduplicate

* fix: bw eink highlights to use the fg colour so saved highlights are visible

* fix: avoid grayscale color in E-ink mode for better legibility

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-02-14 13:32:52 +01:00
Huang Xin ae3bb9da9a fix(annotator): update highlight style, color and range handlers when showing different annotations, closes #3286 (#3289) 2026-02-13 16:46:44 +01:00
Mohammed Efaz 239b32fcc2 fix: reader ruler disabled in scroll mode (#3288) 2026-02-13 16:35:25 +01:00
Huang Xin f64739419b release: version 0.9.100 (#3279) 2026-02-12 18:08:30 +01:00
Huang Xin af8f036ca3 fix(annotator): apply custom highlight colors in sidebar, closes #3273 (#3278) 2026-02-12 17:43:11 +01:00
Huang Xin 24a87508c6 fix(layout): respect image dimension attribute, closes #3274 (#3277) 2026-02-12 16:41:57 +01:00
Huang Xin 548d50a882 fix(tts): navigate to follow the current TTS location for the next section, closes #3198 (#3276) 2026-02-12 16:13:41 +01:00
Huang Xin 1e81ab5205 doc: update sponsor link in README (#3275)
Updated the TestMu AI sponsor link in the README.
2026-02-12 14:10:54 +01:00
Huang Xin a47a480aa2 fix(layout): persistent location for the sidebar toggle, closes #3193 (#3269) 2026-02-11 16:29:26 +01:00
Huang Xin 411f9e236d feat(metadata): support parsing series info from calibre exported EPUBs, closes #3259 (#3267) 2026-02-11 15:39:48 +01:00
Huang Xin 950bbd0821 fix: expose srcdoc also for html sections, closes #3264 (#3266) 2026-02-11 13:15:56 +01:00
Huang Xin 2824e50b51 feat(annotator): snap text selection to word boundary, closes #3234 (#3265) 2026-02-11 12:53:23 +01:00
Huang Xin 129720c916 fix(eink): more legibility for the dictionary and wikipedia popups on Eink devices, closes #3258 (#3262) 2026-02-11 10:22:05 +01:00
Huang Xin fd3533dba1 feat(annotator): add a loupe when adjusting text selection range, closes #3002 (#3261) 2026-02-11 10:13:22 +01:00
Huang Xin 920032155b fix(tts): fix paused tts will still read to the end of the current paragraph, closes #3244 (#3256) 2026-02-11 03:06:12 +01:00
Huang Xin 226bf7033e fix(layout): fixed some layout issues for RSVP, closes #3199 (#3254) 2026-02-10 17:38:33 +01:00
Huang Xin 9444be7fcc feat(annotator): rounded highlight style for horizontal and vertical layout, closes #3208 (#3252) 2026-02-10 16:13:53 +01:00
Huang Xin c9a69a922b fix(layout): workaround for hardcoded table layout, closes #3205 (#3251) 2026-02-10 15:19:36 +01:00
Huang Xin 9a11b05833 fix: don't cache section content when updating subitems, closes #3242 and closes #3206 (#3250) 2026-02-10 14:29:57 +01:00
Huang Xin 6e603ee38f compat: compatibility with older webview on Android, closes #3245 (#3249) 2026-02-10 13:47:25 +01:00
Huang Xin 03fd6e2e6f feat(metadata): collapsible sections in book details, closes #3217 (#3243) 2026-02-09 17:56:34 +01:00
Huang Xin 7dd11c0fb0 fix: fixed docker build by including some dist files in docker image, closes #3233 (#3241) 2026-02-09 15:54:45 +01:00
Huang Xin 968597e52c doc: update toubleshooting and features list, closes #3224 (#3232) 2026-02-09 08:36:16 +01:00
Huang Xin a534050b19 fix(progress): show physical left pages instead of estimated ones, closes #3213 and closes #3200 (#3231) 2026-02-09 05:44:00 +01:00
Huang Xin 0be828fd66 feat(l10n): format sync date time with current locale, closes #3219 (#3230) 2026-02-09 03:09:52 +01:00
Huang Xin c6d4e2bdd6 fix(android): fixed some annotation tools not responsive to tap on Android, closes #3225 (#3229) 2026-02-09 02:26:57 +01:00
Mohammed Efaz bf72ab86cd fix: status button eink compatible (#3223) 2026-02-08 12:28:31 +01:00
Mohammed Efaz fb49ddf484 feat: back button dictionary (#3220)
* feat: add back button with history in dictionry/wikitionary

* fix: flicker back button
2026-02-08 12:27:05 +01:00
Huang Xin d8817a88b9 i18n: add support for Hebrew, closes #3216 (#3218) 2026-02-08 06:55:53 +01:00
Mohammed Efaz 475becafe3 fix: para mode nav buttons issue in eink (#3212) 2026-02-07 17:22:24 +01:00
Mohammed Efaz df165576e6 fix: reader ruler ubresponsive in android (#3210) 2026-02-07 23:16:28 +08:00
Huang Xin 051f2e5b13 fix(layout): show navigation buttons with higher z-index, closes #3201 (#3204) 2026-02-07 10:04:05 +01:00
Huang Xin 83f0d135c5 release: version 0.9.99 (#3190) 2026-02-06 18:51:03 +01:00
Huang Xin 1ed84a3256 feat(tts): navigation in TTS mode with back to current button, closes #3100 (#3189) 2026-02-06 18:26:14 +01:00
Huang Xin 9d6394fe2b fix(layout): fixed page navigation buttons have higher z-index than TTS control button (#3184) 2026-02-06 11:00:56 +01:00
Huang Xin fe9603ffb8 fix(a11y): updating progress info when navigating with screen readers (#3182)
Also add some missing button labels for screen readers
2026-02-06 08:43:03 +01:00
boludo00 681e065ac4 fix(rsvp): fix position restoration and keyboard handling (#3150)
* feat: add RSVP speed reading feature

Implements Rapid Serial Visual Presentation (RSVP) speed reading mode:

- Display words one at a time with ORP (Optimal Recognition Point) highlighting
- Adjustable WPM speed (100-1000) with keyboard/button controls
- Punctuation pause settings (25-200ms)
- Progress tracking with chapter navigation
- Context panel showing surrounding text when paused
- Keyboard shortcuts (Space, Escape, arrows) and touch gestures
- Chapter selector for quick navigation
- Respects current theme colors
- Persists settings (WPM, pause duration, position) per book

New files:
- services/rsvp/RSVPController.ts - Main controller with playback logic
- services/rsvp/types.ts - TypeScript interfaces
- components/rsvp/RSVPOverlay.tsx - Full-screen RSVP reader UI
- components/rsvp/RSVPControl.tsx - Integration component
- components/rsvp/RSVPStartDialog.tsx - Start position selection

Closes #3111

* test(rsvp): add Playwright e2e tests for RSVP feature

- Set up Playwright test infrastructure with config
- Add comprehensive e2e tests for RSVP speed reading:
  - Opening RSVP from View menu
  - Start dialog options
  - Play/pause toggle
  - Speed adjustment
  - Skip navigation
  - Keyboard shortcuts
  - Progress bar
  - Chapter navigation
  - Accessibility tests
- Add test data attributes and ARIA labels to RSVPOverlay
- Add test scripts to package.json

* refactor: remove test files, unsure of use case for now

* chore: remove Playwright e2e test scripts from package.json

- Deleted e2e test scripts related to Playwright from package.json as they are no longer needed.
- Removed Playwright as a dev dependency to streamline the project.

* chore: sync pnpm-lock.yaml after removing @playwright/test

* fix: lint errors and timezone-aware date formatting

* fix(rsvp): restore correct position when exiting RSVP mode

Fix bug where exiting RSVP after changing speed would navigate to wrong
position (several pages backwards). The issue was that Range objects
become stale if the document re-renders, and the position recovery used
global word index instead of per-document index.

- Add docWordIndex to track word position within each document
- Add docTotalWords to RsvpStopPosition for accurate recovery
- Validate Range before using it, recreate from current DOM if stale
- Use same word extraction logic as RSVPController for consistency

* fix(rsvp): prevent arrow keys from changing chapter dropdown

Arrow keys during RSVP mode were inadvertently navigating the chapter
dropdown instead of controlling RSVP speed. Fixed by using capture phase
for keyboard events and stopping propagation to prevent native elements
from receiving the events.

* chore: remove playwright-mcp screenshots from repo

* chore: update gitignore

* fix(i18n): wrap all RSVP overlay strings with translation function

Restore missing translation wrappers for all user-facing strings:
- Close RSVP button labels and tooltips
- Select Chapter dropdown
- WPM display
- Context panel header
- Ready state text
- Chapter Progress label
- Words count and time remaining
- Reading progress slider
- Pause/punctuation label
- Skip back/forward buttons
- Play/Pause button
- Speed control buttons

* fix(rsvp): use CFI-based position tracking for accurate page positioning

- Add CFI generation for each extracted word during RSVP processing
- Implement CFI path and character offset comparison for precise position matching
- Update startFromCurrentPosition to use CFI matching instead of word index
- Add extractFullDocPathWithOffset to handle CFI character offsets
- Simplify RSVPControl by removing unused helper functions
- Remove word index from RsvpPosition in favor of CFI-only tracking

* fix(ViewMenu): re-enable Speed Reading Mode in production environment

* refactor(ViewMenu, RSVPController): clean up code formatting and improve readability

* refactor(ViewMenu): remove unused IoSpeedometer import

* refactor(RSVPController): streamline CFI handling and improve section comparison

- Removed redundant logic and re-using CFI util functions for CFI operations

* refactor(RsvpPosition): remove legacy wordIndex field for cleaner type definition
2026-02-05 18:19:13 +01:00
Huang Xin f64fc5723e fix(a11y): double tap to focus on current paragraph and update page info with TalkBack, closes #2276 (#3179) 2026-02-05 18:18:45 +01:00
Huang Xin a9a1dc8e70 fix(layout): fixed regression of vertical alignment, closes #3012 (#3178) 2026-02-05 17:46:47 +01:00
Huang Xin b1a1e35790 fix(layout): move sync options inside of account section in settings menu (#3176) 2026-02-05 10:08:17 +01:00
Huang Xin 3c538c3746 feat(sync): add manual books sync in the main menu (#3175) 2026-02-05 08:26:33 +01:00
Huang Xin 9834bd57cf feat(toc): add page number for nested TOC items, closes #2953 (#3174) 2026-02-05 08:19:18 +01:00
Huang Xin b89171a4d8 compat(iOS): disable native CompressionStream/DecompressionStream API in zip.js for iOS 15.x (#3170) 2026-02-04 13:18:36 +01:00
Huang Xin 92116e7455 fix(bookshelf): merge groups and ungrouped books then sort them together (#3169) 2026-02-04 12:32:29 +01:00
Huang Xin 8dfab2c963 feat(a11y): always show page navigation buttons in reader page for screen readers, closes #3036 (#3167) 2026-02-04 10:07:37 +01:00
Huang Xin 9f261f12e9 fix(kosync): don't show conflict prompt when progress diff is less than 0.01% (usually from the same device) (#3166)
This should close #3137.
2026-02-04 08:28:15 +01:00
Huang Xin e74615ac1d feat(export): add an option to export annotations as plain text, closes #3147 (#3165) 2026-02-04 07:50:40 +01:00
Huang Xin 3b350d6945 fix(layout): responsive select mode actions on smaller screens (#3164) 2026-02-04 07:04:29 +01:00
Huang Xin 9e0e3fde7d fix(layout): fix aligment of options in settings menu, closes #3151 (#3163) 2026-02-04 06:42:14 +01:00
Adam Charron 52c49ddef1 Add enhanced grouping and sorting functionality to the library view (#3146)
* feat(library): implement grouping of books by series or author

- Added functionality to group books in the library by series or author.
- Introduced new utility functions for creating book groups and parsing author strings.
- Updated the LibraryPageContent to track the current group for navigation.
- Created a new GroupHeader component to display the current group context.
- Enhanced the Bookshelf component to support displaying grouped books.
- Updated settings to include grouping options in the view menu.

New files:
- src/__tests__/utils/libraryUtils.test.ts - Unit tests for new utility functions.
- src/app/library/components/GroupHeader.tsx - Component for displaying group context.
- src/app/library/utils/libraryUtils.ts - Utility functions for grouping and parsing authors.

* Use group by and sort by constants, and split sort/group by menus into their own elements

* Format code with autoformatter

* Remove any casting from tests

* Translate missing strings

* refactor: cleaner layout with collapsible view menu options

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-02-03 14:51:50 +01:00
Huang Xin e3d52891fb fix(a11y): add missing aria labels and fix iOS safe insets (#3149) 2026-02-03 12:50:24 +01:00
Huang Xin 9cd88fe839 fix(progress): show correct progress info for subsections in FB2, closes #3136 (#3145) 2026-02-02 17:53:26 +01:00
Huang Xin fca3917a12 fix(toc): prevent unintentional scrolling in the TOC, closes #3124 (#3144) 2026-02-02 14:28:11 +01:00
Adam Charron c90de6967b Change setup command for vendors in CONTRIBUTING.md (#3139)
Updated instructions for setting up dependencies in the project.
2026-02-02 04:41:54 +01:00
boludo00 bbbd378f9b feat: rsvp speed reading (#3121)
* feat: add RSVP speed reading feature

Implements Rapid Serial Visual Presentation (RSVP) speed reading mode:

- Display words one at a time with ORP (Optimal Recognition Point) highlighting
- Adjustable WPM speed (100-1000) with keyboard/button controls
- Punctuation pause settings (25-200ms)
- Progress tracking with chapter navigation
- Context panel showing surrounding text when paused
- Keyboard shortcuts (Space, Escape, arrows) and touch gestures
- Chapter selector for quick navigation
- Respects current theme colors
- Persists settings (WPM, pause duration, position) per book

New files:
- services/rsvp/RSVPController.ts - Main controller with playback logic
- services/rsvp/types.ts - TypeScript interfaces
- components/rsvp/RSVPOverlay.tsx - Full-screen RSVP reader UI
- components/rsvp/RSVPControl.tsx - Integration component
- components/rsvp/RSVPStartDialog.tsx - Start position selection

Closes #3111

* fix(rsvp): use portal to fix overlay stacking context issue

- Render RSVP overlay and start dialog via React Portal to document.body
- This ensures the overlay appears above all other content regardless of
  parent component CSS transforms or stacking contexts
- Add fallback colors for theme values to ensure solid background

* fix(rsvp): improve UX with progress sync, sentence highlight, and better dialogs

- Fix start dialog transparency by using solid opaque background with proper
  fallback colors for both light and dark modes
- Increase context words from 50 to 100 words before/after current word
- Add progress sync on RSVP exit - navigates reader to the last word position
- Add temporary bright green sentence underline on exit (5 second duration)
  to easily locate where reading left off
- Helper function to expand word range to full sentence boundaries

* fix(rsvp): store full BookNote for proper annotation removal

The addAnnotation API requires the full BookNote object (including CFI)
when removing annotations, not just the ID. Changed tempHighlightIdRef
to tempHighlightRef to store the complete BookNote object.

* test(rsvp): add Playwright e2e tests for RSVP feature

- Set up Playwright test infrastructure with config
- Add comprehensive e2e tests for RSVP speed reading:
  - Opening RSVP from View menu
  - Start dialog options
  - Play/pause toggle
  - Speed adjustment
  - Skip navigation
  - Keyboard shortcuts
  - Progress bar
  - Chapter navigation
  - Accessibility tests
- Add test data attributes and ARIA labels to RSVPOverlay
- Add test scripts to package.json

* fix(rsvp): clarify start dialog option labels

Update the RSVP start dialog to use clearer language:
- "From Beginning" → "From Chapter Start" (since it starts from chapter beginning)
- "From Current Position" → "From Current Page" (starts from visible page)

* fix(rsvp): use correct theme colors from themeCode

The RSVP components were using incorrect palette key names (camelCase
like `base100` instead of hyphenated like `base-100`), causing the
fallback colors to always be used instead of the reader's actual theme.

Fix by using themeCode.bg, themeCode.fg, and themeCode.primary directly,
which are already resolved from the palette with correct keys.

* fix(rsvp): use theme accent color for sentence underline and persist until page change

- Change underline color from hardcoded green (#22c55e) to theme accent
  color (themeCode.primary), matching the ORP focal point highlight
- Remove 5-second timeout that auto-removed the underline
- Add cleanup on page navigation, new RSVP session start, and unmount
- Add removeRsvpHighlight helper function for consistent cleanup

* fix(rsvp): transition to next chapter when reaching end of section

When RSVP reached the end of a chapter, it would restart the current
chapter instead of moving to the next one. This happened because RSVP
extracts ALL words from the current section via renderer.getContents(),
so when words run out, the entire chapter is done.

- Always use view.renderer.nextSection() when RSVP exhausts words
- This moves to the next chapter instead of staying in the current one

* refactor: remove test files, unsure of use case for now

* chore: remove Playwright e2e test scripts from package.json

- Deleted e2e test scripts related to Playwright from package.json as they are no longer needed.
- Removed Playwright as a dev dependency to streamline the project.

* fix(rsvp): ensure CFI retrieval occurs before navigation

- Updated comments to clarify the necessity of obtaining CFI for both the navigation and sentence highlight before invoking the goTo() method, as it may re-render the document and invalidate Range objects.
- Introduced a new variable for sentence text to enhance readability and maintainability of the code.

* chore: sync pnpm-lock.yaml after removing @playwright/test

* style: format RSVP components

* fix: lint errors and timezone-aware date formatting

* i18n: support CJK text and add translations

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-02-01 18:22:24 +01:00
Huang Xin 9f7147f8f8 fix(layout): fix z index for dropdown (#3135) 2026-02-01 16:36:03 +01:00
Huang Xin 8a468a6d1f fix(opds): more robust parsing for authors in metadata, closes #3120 (#3134) 2026-02-01 15:57:10 +01:00
Huang Xin c848a319ff fix(layout): fix centered dropdown menu (#3133) 2026-02-01 15:52:51 +01:00
Huang Xin 5cc80db438 feat(gesture): support two finger swipe left/right to paginate on trackpad, closes #3127 (#3132) 2026-02-01 09:37:13 +01:00
Huang Xin 94930baa1b feat(sync): more intuitive pull down to sync gesture and toast info, closes #3128 (#3131) 2026-02-01 09:23:24 +01:00
Huang Xin 1294ef90c1 fix(macOS): fix traffic lights position and visibility on macOS, closes #3129 (#3130) 2026-02-01 05:38:40 +01:00
Huang Xin 570598520f fix(a11y): fix accessibility in dropdown menus for TalkBack, closes #3035 (#3126) 2026-01-31 19:05:56 +01:00
Huang Xin 7b4fc91994 fix(layout): fixed layout of book reading progress and reader footer bar (#3125) 2026-01-31 18:16:17 +01:00
Huang Xin fb387c2384 fix(layout): fixed layout of book reading progress and reader footer bar (#3117) 2026-01-30 06:54:20 +01:00
Mohammed Efaz 4ce1ebe477 feat: paragraph by paragraph reading mode (#3096)
* feat: add index

* feat: add bottom nav bar

* feat: add paragraph iterator

* feat: add para mode shortcut

* feat: add paragraph control into foliateviewer

* feat: add paragraph mode toggle to view menu

* feat: add paragraph bar for navigation controls

* feat: add paragraph control wrapper component

* feat: add pargraph overlay for the focused display

* feat: integrate paragraph mode into keyboard navigation

* feat: add paragraph mode state management hook

* feat: add paragraph mode type definition

* feat: add default paragraph mode config

* fix: replace previous storage system with sytem one and fix sync issues

* fix: format
2026-01-30 05:24:23 +01:00
Huang Xin c1460f4b85 fix(css): mix blend only inline images, closes #3112 (#3116) 2026-01-30 05:17:16 +01:00
Huang Xin bc94f3f790 refactor: responsive SetStatusAlert on smaller screens (#3110) 2026-01-29 15:53:20 +01:00
Huang Xin c8c761b017 fix(sync): escape unsafe character in filename (#3109) 2026-01-29 15:13:02 +01:00
Huang Xin bdb25999c9 fix(sync): more robust books sync for stale library, closes #3099 (#3108) 2026-01-29 14:05:58 +01:00
Huang Xin c58e172a54 fix(bookshelf): don't show badge or progress for unread book, closes #3103 (#3107) 2026-01-29 12:48:21 +01:00
Huang Xin 160efcd37b chore: bump next.js to the latest version (#3106) 2026-01-29 12:29:17 +01:00
Huang Xin d7470f4139 fix(iOS): disable online catalogs on iOS from appstore channel (#3102) 2026-01-29 05:52:59 +01:00
Mohammed Efaz 01b4e3530d feat: toggle finished manually (#3091) 2026-01-28 06:26:57 +01:00
Huang Xin 09c62d442f fix(css): no default mix blend mode for hr, closes #3086 (#3093) 2026-01-27 15:03:17 +01:00
Huang Xin d62ad60ce8 chore: bump opennextjs and wrangler to the latest versions (#3092) 2026-01-27 14:57:28 +01:00
Jair Goh 8cd34c8aaa feat(assistant): Add embedding model option to AIPanel (#3090)
* Add embedding model option to AIPanel

* Minor code reformatting

* Edit tests to account for embedding model

* Minor reformatting
2026-01-27 14:28:18 +01:00
Mohammed Efaz a52d9e3a2b feat: add fuzzy search for searching across all settings (#3085)
* feat: enable linking to settings items

* feat: integrate command palette with global state and styles

* feat: add command pallete ui and fuzzy search

* feat: add command palette with global state and styles

* feat: add command registry and search dependencies

* fix: open command palette with shortcuts in reader page

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-01-26 18:32:04 +01:00
Huang Xin 64a1ea531a fix(bookshelf): fixed conflicts of group names with common prefix (#3084) 2026-01-26 13:38:01 +01:00
Mohammed Efaz 19f9f5ea24 feat: auto position reader ruler to top of page and some fixes (#3075)
* fix(settings): ensure latest config is used when saving view settings

* fix: reader ruler appearing before other book reading contents

* feat(reader): dispatch reader-closing event during book close

* feat(reader) add auto reposition to top when changing pages and position persistence on book close

* fix(reader): add rtl prop to ReadingRuler component

* fix(reader): handle vertical ltr writing mode in ruler auto positioning

* chore: revert redundant changes to settings.ts

* refactor: remove redundant reader-closing

* refactor: use store progress for ruler positioning with throttled saving
2026-01-26 08:38:06 +01:00
Huang Xin ffc51e75de feat(ruler): support vertical ruler and transparent ruler (#3076) 2026-01-25 20:15:47 +01:00
Huang Xin 2100071991 feat(eink): support color E-ink mode to display more colors, closes #3037 (#3074) 2026-01-25 17:44:41 +01:00
Huang Xin 563d3478ba feat(gamepad): support gamepad input to paginate, closes #2432 (#3073) 2026-01-25 16:32:05 +01:00
Huang Xin 2c54e9ae2f feat(updater): in-app updater for AppImage (#3072) 2026-01-25 14:45:37 +01:00
Huang Xin c2eb2e2fcc doc: update donation link via Stripe (#3071) 2026-01-25 11:24:10 +01:00
Huang Xin e592f40429 layout: don't show upload icon if auto upload is disabled for cleaner UI (#3068) 2026-01-25 09:22:30 +01:00
Huang Xin 4bd7cfe57c chore: fix dockerfile (#3067) 2026-01-25 08:51:40 +01:00
Mohammed Efaz c31ece6742 feat: more highlight colours (#3062)
* feat(highlight): extend types and constants for custom hex colours

* feat(highlight): update colour to support hex strings

* refactor(annotator): update component to accept hex colours

* feat(highlight): add colour picker with max 4 custom colors

* feat(settings): add custom colour editor with limit

* refactor: custom highlight colors can only be modified in settings

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-01-25 07:52:29 +01:00
Mohammed Efaz aba9e87fc1 feat: line highlight to guide reading (reading ruler) (#3063)
* feat: add increment decrement numbers for opacity

* feat: add reading ruler colours

* feat: add reading ruler config to book config

* feat: reading Ruler settings panel (in layout section)

* feat: draggable reading ruler

* feat: reading ruler in reader view
2026-01-25 06:48:13 +01:00
Huang Xin 2c4df601d8 refactor: rename components/ui to components/primitives (#3064)
Move Radix/shadcn-based UI primitives into a dedicated
`components/primitives` directory to better reflect
their low-level, composable nature.
Imports remain ergonomic via an alias to `components/ui`.
App-level components should continue to use PascalCase filenames.
2026-01-25 06:41:18 +01:00
Huang Xin 8bfc90a5b0 chore: fix nunjucks bundling (#3061) 2026-01-24 18:20:15 +01:00
Mohammed Efaz 8bea05478a feat(ai): AI reading assistant phase 2.1 (minor UI/UX updates) (#3059)
* refactor(ai): remove chat icons from conversation list items

* feat(ai): add scroll-to-bottom button with animations and dynamic spacer

* fix(ai): align connection status icon with text in settings

* feat(ai): scroll to bottom on chat panel open and improve scroll behavior

* feat(ai): add loading overlay with blur transition for chat history

* feat(ai): pass loading state through component chain for history loading
2026-01-24 17:57:00 +01:00
Huang Xin 42fee90a27 feat(annotation): export annotations with style and color fields in annotation template, closes #1734 (#3060) 2026-01-24 17:44:40 +01:00
Huang Xin 45e57c3943 chore: update wrangler and next config (#3058) 2026-01-24 14:36:04 +01:00
Huang Xin 51b0b8483f chore: less build concurrency on cloudflare to get rid of build container OOM (#3056) 2026-01-24 13:27:11 +01:00
Huang Xin cbf7a501b7 chore: pin pnpm version for vercel and cloudflare deployment (#3055) 2026-01-24 12:35:03 +01:00
Huang Xin edfcb75ba5 chore: refresh pnpm lockfile (#3054) 2026-01-24 12:08:52 +01:00
Huang Xin ce76843ccc chore: fix patched dependencies (#3053) 2026-01-24 11:52:28 +01:00
Mohammed Efaz 5bbc5ceccc feat(ai): AI reading assistant phase 2 (#3023)
* feat(ai): add dependencies

* chore: bump zod version to default version

* feat(ai): define types and model constants

* feat(ai): ollama provider for local LLM

* feat(ai): implement openrouter provider for cloud models

* feat(settings): register ai settings panel in global dialog

* refactor(ai): expose provider factory and service layer entry point

* test(ai): add unit tests for the providers

* test(ai): add unit tests for the providers

* feat(ai): settings panel for ai configurations

* refactor(ai): rewrite aipanel with autosave and greyed out disabled state

* fix: remove unused onClose prop from aipanel

* test(ai): update mock data

* refactor(ai): remove models

* refactor: use centralised defaults in system defaults

* chore(ai): remove comments

* fix(ai): merge default ai settings on load to prevent undefined values

* refactor(ai): rewrite settings panel with autosave and model input

* feat(ai): add ai tab with simplified highlighting

* feat(sidebar): render AIAssistant for ai tab

* feat(ai): add chat UI

* feat(ai); add chat service with RAG context

* feat(ai): temp debug logger

* feat(ai): add RAG service

* feat(ai): add text chunking utility

* feat(ai): add structured method

* feat(ai): add chatstructured method

* feat(ai): add rag types nd structured output schema

* feat(ai): add aistore, indexdb, bm25

* fix: update lock file

* feat(ai): update types for AI SDK v5

* feat(ai): add placeholder gateway model constants

* refactor(ai): update OllamaProvider for AI SDK

* feat(ai): add native gateway provider

* refactor(ai): update provider exports

* refactor(ai): use streamText from AI SDK

* refactor(ai): use embed from AI sdk

* refactor(ai): update provider factory exports

* feat(ai): add AI Elements and shadcn components

* config: add shadcn component config

* deps: add AI SDK and AI Elements dependencies

* config: add ai packages to transpilePackages

* refactor(ai): remove OpenRouterProvider and old tests

* feat(ai):add assistant-ui components

* feat(ai): add TauriChatAdapter for assistant-ui runtime

* refactor(ai): remove ai-elements components

* dep(ai): install assistant-ui and update next config

* chore(ai): export adapters from service index

* feat(ui): enhance ui components for assistant integration

* feat(settings): migrate ai settings to gateway

* feat(sidebar): integrate assistant-ui

* feat: add ai settings toggle to sidebar content

* feat: conditionally show ai tab in sidebar navigation

* feat: update ai model constants for cheaper options

* feat: add gateway provider with proxied embedding

* feat: add timeouts to ollama provider health checks

* feat: add retry logic to rag service embeddings

* feat: add error recovery to ai store

* feat: add ai feature tests

* feat: add ai api endpoints

* feat: add proxied gateway embedding provider

* feat: add ai runtime utilities

* feat: add ai retry utilities

* feat: add tauri env example template

* feat: add web env example template

* chore: add env

* feat(ai): update models and pricing, remove GLM-4.7-FlashX

* feat(ai): improve system prompt with official headings and no numeric citations

* feat(ai): optimize system prompt for tauri chat

* feat(ui): refine ai chat UI and relocate sources

* feat(ui): update ai settings panel with model pricing and custom model support

* feat(ai): add custom model support to ai settings

* test(ai): update constants tests for removed model

* feat(api): implement ai chat proxy route

* feat(api): implement ai embedding proxy route

* feat(ai): implement ai gateway health check and proxy logic

* feat(ai): simplify proxied embedding provider

* feat(ui): improve markdown text rendering

* feat(ui): add input group component

* test(ai): update ai provider tests

* feat(ai): add pageNumber to text chunk schema

* feat(ai): implement page-based chunking with 1500 char formula

* feat(ai): bump db to v2 and add store reset migration

* feat(ai): transition rag pipeline to page level spoiler filtering

* feat(ai): overhaul readest persona and antijailbreak prompt

* feat(ai): update tauri adapter for page tracking and persona

* chore(ai): export aiStore and logger from core index

* feat(reader): integrate page tracking and manual index reset

* feat(ui): add re-index action and reset logic to chat

* chore: sync pnpm lockfile with ai dependencies

* feat(utils): add browser-safe file utilities for web builds

* refactor(utils): use dynamic tauri fs import to prevent web crashes

* refactor(services): defer osType call to init() for web compatibility

* refactor(services): import RemoteFile from file.web

* refactor(services): import ClosableFile from file.web

* fix(libs): cast Entry to any for getData access

* fix(annotator): cast Overlayer to any for bubble access

* refactor(ai): replace SparklesIcon with BookOpenIcon for index prompt

* test(ai): add pageNumber to TextChunk mocks

* test(ai): fix chunkSection signature in tests

* chore: update files

* fix(ai): prevent useLocalRuntime crash when adapter is null

* refactor: optimize annotator overlay drawing

* feat: stabilize AI assistant runtime and adapter

* refactor: improve document zip loader type safety

* feat: update tauri chat adapter for dynamic options

* fix: restore architecture comments and refine platform properties

* build: update lockfile with assistant-ui patch

* fix(library): patch @assistant-ui/react for runtime initialization

* build: update dependencies in readest-app

* build: update root dependencies and patch configuration

* fix(ai): patch @assistant-ui/react for thread deletion and runtime init

* fix(ai): update assistant-ui patch with dist guards and deletion fallback

* build: sync lockfile with assistant-ui patch updates

* chore(env): update .gitignore by removing .env files from it

* chore(env): update .gitignore by adding .env.local

* chore(env): update .gitignore by adding .env*.local

* fix: restore static osType import

* chore: sync submodules with upstream/main

* refactor: remove redundant file.web module and revert import

* chore: update pnpm-lock.yaml

* refactor: revert guards

* refactor; remove deprecated codes and extract prompts.ts

* refactor(ai): remove unused ragservice exports

* refactor: remove unused ollama and embedding models

* refactor: remove unused type

* test: remove test for the now deleted constants

* refactor: remove unused export

* style: fix ui component formatting

* style: fix core and style file formatting

* test: fix broken ai provider import

* fix: typescript error

* fix: add eslint disable command

* fix(deps): remove unused ai sdk provider util after v6 ai sdk migration

* fix(patch): add lookbehind regex patch

* feat(dep): upgrade vercel ai sdk to v6 and ai-sdk-ollama to v3

* chore: update lockfile for vercel ai sdk v6

* refactor(ai): remove EmbeddingModel generic for ai sdk v6

* refactor(ai): remove EmbeddingModel generic for ai sdk v6

* test(ai): update mock to use embeddingModel

* fix(patch): add lookbehind regex patch for email autolinks in markdown

* refactor(ai): use ai sdk v6 syntax

* fix: prettier formatting

* chore: revert cargo.lock

* fix(ai): update proxied embedding model to v3 spec

* feat(ai): add aiconversation types for chat persistence

* feat(ai): add conversation/message indexeddb and crud operations

* feat(ai): create aiChatStore zustand store for chat state management

* feat(notebook): add notebookactivetab state for Notes/AI

* refactor(ai): refine conversation and message types for persistence

* feat(types): add notebookActiveTab to ReadSettings type

* chore: update deps

* feat: add notebookactive tab default value

* feat: add hook for ai chat

* feat: update left side panel with history/chat icon

* feat: integrate ChatHistoryView into sidebar content

* feat: create UI for managing AI chat history

* feat: implement persistent history with assistant-ui adapter

* feat: create tab navigation component for notes and AI

* feat: add tab navigation and AI assistant view

* feat: update header to display active tab title

* fix: formatting

* feat: remove title and update new chat button

* fix: formatting

* fix: revert tooltip and styling

* feat: implement cross-platform ask dialog bridge

* feat(ai): preserve history during ui clear & use native dialogs

* fix: align notebook navigation height with sidebar tabs

* fix(ai): add missing dependency to handleDeleteConversation hook

* docs: update PROJECT.md with session highlights

* chore: delete projectmd

* chore: update package.json and lock file

* chore: update package.json

* chore: remove patch

* chore: upgrade react types to 19 and show ai features only in development mode for now

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-01-24 11:38:48 +01:00
Huang Xin 224acd68b1 fix(sanitizer): add XHTML11 doc type to recognize nbsp entity, closes #3024 (#3043) 2026-01-23 17:49:06 +01:00
Huang Xin 6c0f1b8b5f fix(annotator): fix instant action on Android (#3042) 2026-01-23 17:18:51 +01:00
Huang Xin 481d8198e9 fix(tts): set playback rate after play only on Linux (#3040) 2026-01-23 12:14:13 +01:00
Huang Xin b1153ba051 fix(sync): correctly update last sync timestamp when the bookshelf has no books yet (#3039) 2026-01-23 04:39:22 +01:00
Huang Xin aad532bfdd fix(sync): hotfix for the initial race condition for books sync (#3038) 2026-01-23 04:32:03 +01:00
Huang Xin a71347c897 fix(layout): more responsive layout on smaller screens, closes #3029 (#3034) 2026-01-22 17:32:34 +01:00
Huang Xin 034f41ca10 fix(shortcuts): prevent system search bar from showing with ctrl+f, closes #3013 (#3033) 2026-01-22 15:59:21 +01:00
Huang Xin 539ad8dea2 fix(layout): correctly constrain the maximum width of fixed-layout tables, closes #3028 and closes #3017 (#3032) 2026-01-22 14:56:35 +01:00
Huang Xin 48920a87bf chore(opds): disable popular online opds catalogs in certain regions on App Store (#3031) 2026-01-22 11:42:16 +01:00
xijibomi-coffee d1d0d2d59c chore: enforce prettier, ignore submodules and vendor files (#3018)
* chore: enforce prettier, ignore submodules and vendor files

* chore: add format check in CI

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-01-21 14:53:02 +01:00
xijibomi-coffee ea811c90c6 feat(ui): switch typography to Inter (#3009) 2026-01-21 13:49:37 +01:00
Jon Volkmar 5cd5b65e83 fix: Conditionally set Cache-Control header to prevent caching in development environments. (#3010) 2026-01-21 03:18:08 +01:00
Huang Xin ea24b5a97a fix(account): redirect to auth page if unauth user is in user page (#3008) 2026-01-20 21:55:53 +01:00
Huang Xin 06d620db83 chore: fixed signing of the portable version for Windows (#3007) 2026-01-21 03:23:39 +08:00
Huang Xin 0c25b85a8a release: version 0.9.98 (#3006) 2026-01-20 18:54:06 +01:00
Huang Xin c536450ab0 fix(fonts): host fonts in Readest CDN for more stable web fonts distribution (#3005) 2026-01-20 18:44:22 +01:00
Huang Xin c83e380c5a chore(doc): use png resources for sponsors logo (#3003) 2026-01-20 07:47:28 +01:00
Huang Xin 894a7551aa chore(doc): update sponsors info (#3002) 2026-01-20 07:42:06 +01:00
xijibomi-coffee f875ba88ac perf: use native walkdir for recursive imports from directory (#2993)
* fix(perf): replace JS recursion with native Rust walkdir for imports

* fix: implement security scope check in rust recursive scanner

* refactor and format code

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-01-20 06:22:04 +01:00
Huang Xin d9a6cffe78 feat(discord): support show reading status with Discord Rich Presence, closes #1538 (#2998) 2026-01-19 17:42:19 +01:00
Huang Xin 1704736bc8 feat(account): support social login with Discord account (#2995) 2026-01-19 05:22:17 +01:00
Huang Xin 6ce9a263ee fix(a11y): add missing aria labels for some buttons on TTS panel (#2994) 2026-01-19 04:29:02 +01:00
Huang Xin 038eca4267 fix(eink): resolved an issue where the dropdown menu would occasionally fail to expand on some Eink devices (#2991) 2026-01-18 19:57:09 +01:00
Huang Xin f0722ec0fe feat(bookshelf): show one line of book description in list view of the bookshelf, closes #2955 (#2990) 2026-01-18 17:16:54 +01:00
Huang Xin fd299a61a7 feat(notes): export notes with custom template, closes #1734 (#2989) 2026-01-18 16:56:32 +01:00
Huang Xin 36b7386e30 fix(portable): in-app update the portable version app, closes #2983 (#2988) 2026-01-18 11:20:15 +01:00
Huang Xin 2670b0dc0b fix(linux): use new AppImage format on Linux, closes #190 (#2985)
See https://github.com/tauri-apps/tauri/pull/12491
2026-01-18 09:50:51 +01:00
Huang Xin c44705e269 perf(pdf): pre-render next page for PDFs (#2984)
This should close #1911 and #13.
2026-01-18 08:58:00 +01:00
Huang Xin 7e618d456e chore: bump pdf.js to the latest version (#2982) 2026-01-17 13:45:34 +01:00
Huang Xin b28ac99a9e feat(pdf): support panning on PDFs (#2981)
This also closes #2978 and closes #2875.
2026-01-17 09:11:33 +01:00
Huang Xin 2d7d6b08a9 compat(opds): parse attachment filename from download requests, closes #2969 (#2976) 2026-01-16 17:13:30 +01:00
Huang Xin b1419f9c01 chore: bump tauri to latest dev (#2975) 2026-01-16 14:52:22 +01:00
Huang Xin 32ea42a835 fix: remove non-breaking space in book title (#2974) 2026-01-16 12:02:41 +01:00
Huang Xin 6083de3293 fix(import): read permissions of nested directories when importing books, closes #2954 (#2972) 2026-01-16 08:04:07 +01:00
Huang Xin 1c9cfa49b3 fix(flathub): use custom dbus id for single instance on Linux (#2971) 2026-01-16 05:59:25 +01:00
Huang Xin f85d6d4293 fix(eink): avoid scrolling if animation is turned off or in eink mode, closes #2957 (#2967) 2026-01-15 17:37:38 +01:00
Huang Xin 017d0b0b39 fix(tts): fix setting playback rate on Linux, closes #2950 (#2966) 2026-01-15 17:29:26 +01:00
Huang Xin 3146ae48a7 fix(proofread): support replace text with space (#2965) 2026-01-15 14:10:05 +01:00
Huang Xin 7f26e45ae7 feat(sync): cloud deletion in transfer queue (#2964) 2026-01-15 13:50:24 +01:00
Huang Xin 7d97826e4b feat(tts): replace words for TTS, closes #2057 (#2952) 2026-01-14 16:42:11 +01:00
Huang Xin 9c9c79176d feat(bookshelf): add an option to sort books by publish date, closes #2925 (#2949) 2026-01-14 13:40:07 +01:00
Huang Xin ed476a4fce fix(ios): fix wakelock on iOS, closes #2453 (#2948) 2026-01-14 13:06:16 +01:00
Huang Xin 44b4f7995b fix(android): fix annotator on Android, closes #2927 (#2946) 2026-01-14 11:56:38 +01:00
Huang Xin da5e3a0bd3 perf(fonts): cache first for font cache (#2945) 2026-01-14 07:34:00 +01:00
Huang Xin ba4678cc23 fix(fonts): fix CORS access error 403 of deno.dev with Origin: tauri://localhost (#2944) 2026-01-14 05:35:27 +01:00
Huang Xin e5eb3014b4 chore(unittest): test makeSafeFilename (#2943) 2026-01-14 04:08:30 +01:00
Huang Xin ed77b0bc7f fix(android): only dismiss unpinned sidebar and notebook with back key, closes #2920 (#2939) 2026-01-13 15:42:03 +01:00
Huang Xin 434a44e62c feat(proofread): add an option for whole word replacement, closes #2934 (#2938) 2026-01-13 15:35:57 +01:00
Huang Xin aaee04c290 fix(opds): probe filename when downloading PDFs and CBZ files, closes #2921 (#2932) 2026-01-12 17:55:50 +01:00
Huang Xin 48e2bfa82c fix(android): avoid occasional crash on start on Android (#2931) 2026-01-12 16:27:25 +01:00
Huang Xin c04f19ffb4 feat: add support for exporting book files in book details dialog, closes #2919 (#2930) 2026-01-12 16:26:32 +01:00
Huang Xin 4a624e3902 fix(settings): avoid stale viewSettings after saving, closes #2912 (#2916) 2026-01-11 16:47:36 +01:00
Huang Xin f53cee9616 release: version 0.9.97 (#2909) 2026-01-10 15:51:20 +01:00
Huang Xin 30385ee5ec fix(settings): correctly setting configs for selected book in parallel read, closes #2825 (#2908) 2026-01-10 15:01:04 +01:00
江夏尧 b30dfb3e23 fix(fonts): update font CDN links to use deno.dev for improved reliability (#2906) 2026-01-10 13:47:19 +01:00
Huang Xin c0d6102857 fix(css): primary btn style for e-ink mode (#2905) 2026-01-10 13:13:32 +01:00
Huang Xin 4537c55e84 fix(css): respect css for page break and minimum font size, closes #2895 (#2903) 2026-01-10 10:30:21 +01:00
Huang Xin aff94c0ab8 fix(windows): update shortcut to point to current installation, closes #2878 (#2902) 2026-01-10 10:26:32 +01:00
Huang Xin fd70836308 fix(windows): update shortcut to point to current installation, closes #2878 (#2901) 2026-01-10 09:53:40 +01:00
Huang Xin 1b0c94b9a5 fix(opds): temporary workaround for self-signed cert for OPDS server, closes #2871 (#2900)
Related to https://github.com/seanmonstar/reqwest/issues/1554
2026-01-10 08:47:12 +01:00
Huang Xin 7cb523eefc fix(metadata): no need to download book to display book details, closes #2857 (#2897) 2026-01-09 15:58:01 +01:00
Huang Xin 941be80cc4 fix(css): table and header layout, closes #2874 (#2896) 2026-01-09 15:06:37 +01:00
Huang Xin 5eecc735aa fix(proofread): support text replacement for text with no word boundaries, closes #2889 (#2894) 2026-01-09 10:27:38 +01:00
Huang Xin cfe51d01ee fix(sanitizer): normalize non-breaking spaces for WebView compatibility (#2893)
Convert &nbsp; to &#160; before sanitization and restore after XMLSerializer
serialization. This handles the platform difference where XMLSerializer
produces different representations of non-breaking spaces (&nbsp;, &#160;,
or \u00A0) across different WebView implementations.
2026-01-09 09:30:04 +01:00
Huang Xin 20ae09c52d perf(sync): persist partial library sync to prevent full retry on failure (#2892) 2026-01-09 09:23:02 +01:00
Huang Xin b868146129 feat(config): add an option to toggle footbar by tapping on the footbar (#2891) 2026-01-09 03:22:34 +01:00
Hermotimus a312080f7c fix(tts): footnotes anchors and superscript filtering (#2890) 2026-01-09 02:16:07 +01:00
Huang Xin 462ca46fee feat(eink): optimize color and layout for e-ink mode (#2887) 2026-01-08 17:29:33 +01:00
Huang Xin 93228c4b2a fix: avoid hydration mismatch for tauri app (#2884) 2026-01-08 04:05:10 +01:00
Huang Xin 2ff10f781f feat(annotator): support vertical layout for annotation editor (#2882) 2026-01-07 16:18:57 +01:00
Huang Xin 9614c62360 feat(annotator): instant highlighting with mouse, touch or pen (#2881) 2026-01-07 16:13:37 +01:00
lcd1232 5ffaac5e67 fix(login): fix login message field (#2879) 2026-01-07 12:55:11 +01:00
Huang Xin 71af91608f feat(annotator): support editing text range of highlights (#2870) 2026-01-05 16:25:58 +01:00
Huang Xin 9603b61776 refactor(annotatot): more cleaner text selector on Android (#2867) 2026-01-05 08:53:38 +01:00
Huang Xin eed84a059a fix(search): should be able to terminate search when sidebar is invisible (#2863) 2026-01-04 17:10:49 +01:00
Huang Xin 604ef65719 perf(search): use cache for search results (#2861) 2026-01-04 12:56:40 +01:00
Huang Xin 483d536ca4 feat(search): support search terms history, closes #2836 (#2859) 2026-01-04 07:47:43 +01:00
Huang Xin 69a51c5880 compat(footnote): support alt footnote inside placeholder anchor (#2858) 2026-01-04 06:06:24 +01:00
Huang Xin ca8d25341e compat(opds): support Komga OPDS v1.2 and v2, closes #2839 (#2851) 2026-01-03 18:04:39 +01:00
Huang Xin 8a263235ed feat(search): add annotations navigation bar, closes #2060 (#2849) 2026-01-03 14:57:10 +01:00
Huang Xin fb41ff5d0c fix(tts): reduce the pause duration between sentences in Edge TTS, closes #2837 (#2844) 2026-01-03 08:44:15 +01:00
Huang Xin a5e09e8454 feat(search): add search results navigation bar, closes #1183 (#2842)
Add a floating navigation component that appears when search results exist.
The component includes:
   - Top bar: displays search term and current section with TOC and close buttons
   - Bottom bar: search results, previous, and next navigation buttons
   - Page-based navigation using isCfiInLocation to skip between pages with results
2026-01-03 08:10:23 +01:00
Huang Xin 730ee21651 fix(android): don't navigate back with the back button for more predictable navigation (#2835)
This will revert the link navigation with back button in #2454.
This will close #2833 and more user reports that found back link navigation confusing.
2026-01-02 15:44:47 +01:00
Huang Xin dea43445c3 fix(layout): set image width for vertical inline images (#2832) 2026-01-02 14:54:02 +01:00
Huang Xin 4f0ae78d43 fix(ios): fixed error when importing file with urlencoded names (#2831) 2026-01-02 14:35:11 +01:00
Huang Xin d9116d619a feat(css): support overriding link color (#2830) 2026-01-02 14:15:02 +01:00
Huang Xin c080e6fdd3 fix(metadata): fixed sometimes svg book cover is rendered blank (#2829) 2026-01-02 14:13:24 +01:00
Huang Xin d3752dadc6 fix(library): upload files also for open with import and opds import, closes #2826 (#2827) 2026-01-02 13:32:52 +01:00
André Angelantoni e21ef53a3d fix(settings): ensure global settings sync across all open panes (#2818)
* fix(settings): ensure global settings sync across all open panes

Previously, changing a global setting (like font size) only updated the currently active book pane, causing split-view panes to desynchronize.

This commit updates the settings logic to propagate global changes to all open book instances immediately. It also ensures that settings UI panels correctly re-render when preferences are updated from outside the component.

* refactor to reuse some code

* fix: pointer in doc check

---------

Co-authored-by: André Angelantoni <andre.angelantoni@performantlabs.com>
Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-01-01 07:12:07 +01:00
Huang Xin 71e97998b6 feat(transfer): add a background transfer queue system for book uploads/downloads (#2821) 2025-12-31 08:40:28 +01:00
Huang Xin 22f9c45232 fix(annotator): delay highlight action to prevent immediate onShowAnnotation trigger (#2820) 2025-12-31 08:35:26 +01:00
Huang Xin a42897ec5c feat(annotator): support quick actions for text selection, closes #2505 (#2813) 2025-12-30 10:32:01 +01:00
Huang Xin 58a5c1625c fix(css): only override background color of hr when it has background image (#2808) 2025-12-30 10:24:37 +01:00
Huang Xin d53fc09e1e chore: bump opennext, wrangler and serwist to the latest versions (#2807) 2025-12-29 05:12:32 +01:00
Huang Xin 11fecb5dc0 chore: bump tauri to latest dev (#2805) 2025-12-29 04:07:58 +01:00
Huang Xin f4587663b5 chore(ios): drop support for iOS below 15.0 (#2804) 2025-12-29 03:41:12 +01:00
Huang Xin b76a2adf61 compat(epub): detect missing writing direction for some EPUBs (#2803) 2025-12-28 19:43:49 +01:00
Huang Xin 988fbc8c85 fix(settings): override book text align of left (#2802) 2025-12-28 18:02:56 +01:00
Huang Xin f944ad9b9f feat(annotator): support rendering vertical annotation bubbles (#2801) 2025-12-28 13:52:12 +01:00
Huang Xin 335d91b9c9 fix(layout): dismiss annotation popup on mobile when navigating (#2799) 2025-12-28 07:18:03 +01:00
Huang Xin 173404eaad feat(annotator): show notes popup when annotation bubble icon is clicked, closes #1845 (#2798) 2025-12-27 17:31:47 +01:00
Huang Xin 674fed5230 fix(annotator): adjust underline position to the center of two lines, closes #2772 (#2793) 2025-12-26 09:51:02 +01:00
Huang Xin 12d284cd22 fix(layout): fixed line clamp for config items on small screens (#2792) 2025-12-26 05:05:37 +01:00
Huang Xin 77037c8adb fix(sw): use NetworkFirst for navigation to prevent blank page on updates (#2784) 2025-12-24 15:19:14 +01:00
Huang Xin 6984393ed1 refactor(proofread): refactor UI and i18n for proofread tool (#2783) 2025-12-24 14:46:33 +01:00
Huang Xin 3abef6ea75 fix(opds): correctly parse file extension for CBZ files from OPDS servers, closes #2765 (#2771) 2025-12-23 08:53:50 +01:00
Huang Xin 4ae1ab7dd0 fix(layout): workaround for hardcoded image container (#2769) 2025-12-23 06:31:09 +01:00
Huang Xin 69fb22119b fix(layout): tweak insets for vertical layout (#2767) 2025-12-23 06:01:06 +01:00
Huang Xin 3a6c18c6d5 feat(font): support OpenType feature of vrt2 and vert for vertical replacement of some punctuations (#2764) 2025-12-22 18:39:09 +01:00
Huang Xin 7db1bc460d chore(pwa): migrate from next-pwa to serwist (#2762) 2025-12-22 16:10:09 +01:00
Huang Xin a460e609fa refactor(file): avoid eviction race of chunks cache (#2761) 2025-12-22 05:59:40 +01:00
Huang Xin 4b4ebdbdaa fix(pdf): avoid frequent eviction of chunk cache from worker thread, closes #2757 (#2759) 2025-12-21 17:47:41 +01:00
Huang Xin 9358a06839 compat(layout): grid layout with fit covers on older browsers, closes #2745 (#2756) 2025-12-21 08:52:57 +01:00
Huang Xin a7baf6cc9f fix(tts): prompt users to log in to use Edge TTS on the web version (#2749) 2025-12-19 17:54:17 +01:00
Huang Xin 15dc669f35 chore: update app metainfo (#2744) 2025-12-19 04:54:24 +01:00
Huang Xin c853957512 release: version 0.9.96 (#2743) 2025-12-19 03:54:17 +01:00
Huang Xin 8a4e22e423 refactor: temporarily disable the proofreading feature for a hotfix release ahead of a major refactor (#2742) 2025-12-19 03:45:42 +01:00
Huang Xin 8a43c58fd4 fix(tts): resolve Edge TTS being blocked in certain regions (#2741)
This should close #2739 and close #1821.
2025-12-19 03:24:51 +01:00
Qianxue Ge 54fdf5f1fd feat(replacement): text replacement feature for EPUB books (#2725)
* add: basic ui replacement menu

* feat(replacement): modified ViewSettings interface and added Replacement type

* add: frontend menu ui to annotation settings
- create replacementoptions file for 4 fix options: fix once, fix in library, fix in book, fix in library
-integrate with annotator.tsx
only frontend changes, but initialzied in backend

* add: delete global option and click gear option to get rid of menu

* docs: add test cases for replacementoptions file

* edits to enable readest to build

* basic changes for rule types

* replacement transformer file added

* additional support code added

* interim updates to replacement.ts file

* adding console log statements to confirm functionality without frontend

* adding more console logs for debugging; i think i got my replacement working, will clean console logs and add actual tests now.

* figured out how to get my transformer to work. replacement doesnt actually work yet. figuring that out rn. committing before i destroy something, lol

* replcement logic working with hard coded tests. code is cleaned up with minimal console logs. actual replacement logic + testing is next :)

* test suite built, and fully passing. made consle log edits too.

* added more replacement rules, but figuring out why they arent being implemented by my code.

* cleaning up test suite to not break when there are 0 rules; test is commited with 1 local rule. not sure if that rule is going to copy over when i merge.

* feat(replacement): Add text field, case sensitivity checkbox, and confirmation dialog to ReplacementOptions

- Add text input field for replacement text with placeholder
- Add 'Case Sensitive' checkbox (default: unchecked/case-insensitive)
- Implement two-step confirmation flow with Back/Confirm buttons
- Show preview of original text, replacement text, scope, and case sensitivity
- Disable scope buttons until replacement text is entered
- Display truncated preview for long selected text (>50 chars)
- Export ReplacementConfig type for use in parent components

* feat(replacement): Add 30-word limit and integrate new ReplacementOptions component

- Add MAX_REPLACEMENT_WORDS constant (30 words)
- Add getWordCount() utility function for word counting
- Show warning toast when word limit exceeded on Text Replacement click
- Replace old fix handlers with single handleReplacementConfirm()
- Integrate with new ReplacementConfig (replacementText, caseSensitive, scope)
- Display success toast with scope and case sensitivity info on confirm

* fix(build): Add ReplacementMenu placeholder component

- Create placeholder component to fix missing import error in reader/page.tsx
- Component returns null for now, to be implemented with global replacement rules

* test(replacement): Add comprehensive tests for ReplacementOptions and word limit

ReplacementOptions.test.tsx:
- Test rendering of text input, checkbox, and scope buttons
- Test case sensitivity checkbox toggle and state
- Test disabled buttons when no replacement text entered
- Test confirmation dialog flow and Back/Confirm buttons
- Test click outside and Cancel button behavior
- Test full replacement flow with all options

wordLimit.test.ts:
- Test word counting with various inputs (spaces, newlines, unicode)
- Test 30-word limit boundary conditions
- Test case-sensitive vs case-insensitive matching logic
- Test edge cases (empty string, long words, punctuation)

* refactor: removed unused initial definition of Replacement

* feat: added replacement rules window in bookmenu

* test: added tests to verify the replacement rules window renders book and global replacement rules, and it opens when bookmenu item is clicked

* feat: added Replacement tab in SettingsDialog, displays global rules

* feat(replacement): connected front-end to functions. todo: fix the automatic reload functionality.

* fix(replacement): simplified re-rendering logic, doesn't fail on epubs anymore.

* test: add integration tests for text replacement functionality

* fix: added single rules section to ReplacementRulesWindow

* fix(replacement): added null checks to some unsafe calls in integration tests

* fix(replacements): added non-null assertion operator for a previously initialized variable

* refactor: created ReplacementPanel and edited style of inputs

* feat: disable the edit feature for selected phrase

* refactor: use toast instead of banner for confirmation msg

* feat: automatically reload the page to apply changes

* feat: disable global rule for book if deleted in book view

* fix(replacement): Improve popup positioning and eliminate ghost animation

- Add viewport boundary detection to keep popup within visible area
- Calculate position only once on mount to prevent jumping when other UI appears
- Use visibility: hidden until position is calculated to eliminate ghost animation
- Add max-height with overflow-y: auto for scrollable content
- Popup now appears directly in correct position without two-step animation

* fix: implement single-instance replacement with persistence

- Add sectionHref to TransformContext for section tracking
- Add singleInstance, sectionHref, occurrenceIndex fields to ReplacementRule
- Pass section name from FoliateViewer to transformer context
- Switch transformer from DOM-based to string-based replacement
- Handle single-instance rules with section matching and occurrence tracking
- Update Annotator to track occurrence index and apply direct DOM changes
- Persist single-instance rules for refresh survival

Single-instance replacements now:
1. Apply immediately via direct DOM modification
2. Store occurrence index and section for precise targeting
3. Persist across page refreshes

* fix: allow multiple single-instance replacements for same word

Single-instance rules now always create new entries instead of merging.
This fixes the issue where replacing multiple occurrences of the same
word would overwrite previous rules.

The transformer applies rules in sequence, so each rule targets
occurrence index 0 of the current (modified) string, allowing
cascading replacements to work correctly after refresh.

* fix: prevent cascading replacements and add wholeWord support

- Add wholeWord field to ReplacementRule for word boundary matching
- Track replaced regions to prevent replacement text from being re-matched
- Fix cascading replacement issue where replacement text was matched again
- Apply replacements from right to left to preserve positions
- Support whole word matching with \b boundaries for both single-instance and regular rules

* Fix whole-word matching for replacement rules

- Auto-enforce whole-word matching for simple word patterns (letters only)
- Add HTML tag boundary checks to prevent matching across tags
- Add double-check validation for whole-word matches
- Prevent matching 'and' inside words like 'England', 'stand', 'understand'
- Add comprehensive logging for debugging replacement issues

* test: added rAF in setup to for ReplacementOptions tests

* fix: only allow replacement for epubs, remove replacement rendering for non-epubs, add test cases

* refactor: refactored replacement logic for case sensitivity and word boundaries

* test: added tests for scope precedence and case sensitivity across scopes

* refactor: removed unnecessary code from testing

* feat: able to display, edit, and delete single-instance rules in book settings

* fix: connected case sensitive checkbox to backend, fixed merge and delete logic

* test: updated test cases to reflect changes on case sensitivity and rules rendering

* test: modified ReplacementOptions test to remove unnecessary case sensitive check from merge

* fix: add logic for grayed out button for non-epubs

* chore: update foliate-js submodule from upstream merge

* fix: resolve all TypeScript/ESLint linting errors

- Fix prefer-const error in ReplacementOptions.tsx
- Fix set-state-in-effect error in ReplacementRulesWindow.tsx (use lazy initializer)
- Replace all @typescript-eslint/no-explicit-any with proper types (ReplacementRule, unknown, etc.)
- Fix unused error variables in replacement.ts (prefix with _)
- Remove unused eslint-disable directives
- Add missing ReplacementRule import in ReplacementPanel.tsx

* fix: add localStorage mock to vitest setup

- Fixes test failures in ReplacementRulesWindow and SettingsDialog tests
- localStorage mock ensures all Storage API methods are available in test environment

* fix: resolve ESLint and TypeScript build errors

- Fix all remaining @typescript-eslint/no-explicit-any errors in test files
- Fix unused error variables in replacement.ts (prefix with _)
- Fix TypeScript error in ReplacementRulesWindow.tsx (move @ts-ignore to correct location)
- All ESLint checks now pass
- Web and Tauri builds compile successfully

* fix: remove lookbehind regex for browser compatibility

- Replace lookbehind assertions (?<!...) with manual boundary checking
- Add isUnicodeWordChar helper function for manual Unicode word boundary detection
- Apply manual boundary checks in applyMultiReplacement and applySingleInstance
- Fixes build_web_app check failures by avoiding lookbehind in compiled output
- Maintains whole-word matching functionality for both ASCII and Unicode patterns

* fix: update tauri-utils version to 2.8.1 to resolve duplicate symbol error

- Update local tauri-utils version from 2.8.0 to 2.8.1 to match crates.io version
- Fixes duplicate symbol __TAURI_BUNDLE_TYPE linker error
- Ensures all dependencies use the same tauri-utils version

* fix: use local tauri path directly to resolve version conflicts

- Change tauri dependency to use local path instead of version requirement
- This ensures all dependencies use the same local tauri version (2.9.3)
- Fixes 'links = Tauri' conflict error in Rust linting
- The patch.crates-io should still work for transitive dependencies

* fix: use version requirement with patch for tauri dependency

- Revert to using version requirement '2' instead of direct path
- Rely on [patch.crates-io] to use local tauri version
- Remove Cargo.lock to force fresh dependency resolution
- This should resolve the 'links = Tauri' conflict by ensuring
  all tauri dependencies (direct and transitive) use the patched version

* fix: remove plugin patches that cause resolution errors

- Remove all tauri-plugin git patches from [patch.crates-io]
- Keep only tauri, tauri-utils, and tauri-build patches
- Plugins from crates.io will use the patched tauri via transitive dependencies
- Fixes error: patch for tauri-plugin-oauth failed to resolve

* fix: update tauri submodule with tauri-utils version fixes

* fix: revert tauri submodule and update tauri-utils to 2.8.0

- Revert submodule changes that can't be pushed to remote
- Update local tauri-utils version to 2.8.0 to match other packages
- This avoids the need to modify the submodule

* fix: add tauri-plugin to workspace and patch to resolve duplicate symbol error

- Add packages/tauri/crates/tauri-plugin to workspace members
- Add tauri-plugin patch to [patch.crates-io]
- This ensures all tauri dependencies use local versions
- Fixes duplicate symbol __TAURI_BUNDLE_TYPE linking error

* chore: restore Cargo.lock from upstream

- Restore the original Cargo.lock from readest/readest main branch
- This ensures reproducible builds and matches upstream
- The lock file will be updated by cargo when dependencies change

* fix: resolve TypeScript errors in test files

- Fix ReplacementOptions.test.tsx: add optional chaining for possibly undefined values
- Fix ReplacementRulesWindow.test.tsx: use proper type assertions for store setState calls
- Use (store.setState as unknown as (state: unknown) => void) pattern for partial state updates

* fix: prevent race condition when deleting replacement rules rapidly

- Add isReloading state to track ongoing delete/edit operations
- Prevent multiple rapid deletions that cause runtime errors during page reload
- Show warning toast when user tries to delete while reload is in progress
- Add finally blocks to ensure isReloading is always reset
- This prevents the 'book doesn't finish rerendering' error

* fix: allow phrases and lines with quotes for single-instance replacements

- Updated isWholeWord() to allow phrases (text with spaces or punctuation)
- Phrases are always allowed for single-instance replacements
- Only single words are checked for partial word matches
- Fixes issue where lines with quotes couldn't be replaced
- Added detailed logging for debugging phrase detection

* fix: allow selections with boundary punctuation and fix pattern matching for punctuation

- Updated isWholeWord() to explicitly allow selections that start or end with punctuation (e.g., 'tis, off;, look,)
- Fixed normalizePattern() to handle patterns with leading/trailing punctuation correctly
- Word boundaries are now only added around the word part, not the punctuation
- Fixes issue where replacements like 'scholar;' were not matching correctly

* fix: escape HTML entities in replacement text to preserve angle brackets

- Added escapeHtmlEntities() function to escape HTML special characters
- Apply HTML escaping to replacement text in both multi and single-instance replacements
- Fixes issue where replacement text like '<<AND>>' was being interpreted as HTML tags
- Angle brackets and other HTML entities are now properly escaped and displayed correctly

* fix: revert Tauri backend changes and resolve package.json conflict

- Revert Cargo.toml and src-tauri/Cargo.toml to match upstream/main
- Resolve @tauri-apps/cli version conflict (2.9.5 -> 2.9.6)
- These changes are not related to the replacement feature implementation

* fix: update pnpm-lock.yaml to match @tauri-apps/cli 2.9.6

* removed useless tests and backend tests from ReplacementOptions integration testing suite

* chore: revert foliate-js submodule to match readest/readest main

* fix: refactored wordLimit logic into a separate util file

* fix: removed additional pr description

* refactor: rewrite replacement transformer to use DOM-based approach
replace string manipulation with DOMParser and TreeWalker
follow pattern from simpleecc transformer

* style: format code with prettier

* fix: remove unused string-manipulation functions

* fix: refactored display dialog logic to match other dialogs

* fix: enabled global rule deletion in book menu

* fix: removed ReplacementPanel from library settings

* fix: deleted SettingsDialog.replacement.test.tsx since we no longer need to display replacements in library settings

* fix: removed text replacement tab from settings dialog

* fix: applied prettier code formatter to replacement rules window

* chore: fix formatting and remove unused file listed by chrox

* chore: format all changed files from pr 2693 and revert pnpm-lock

* rebased Cargo.lock, package.json, pnpm-lock.yaml to upstream main
edits to enable readest to build

* basic changes for rule types

* replacement transformer file added

* additional support code added

* interim updates to replacement.ts file

* adding console log statements to confirm functionality without frontend

* adding more console logs for debugging; i think i got my replacement working, will clean console logs and add actual tests now.

* figured out how to get my transformer to work. replacement doesnt actually work yet. figuring that out rn. committing before i destroy something, lol

* replcement logic working with hard coded tests. code is cleaned up with minimal console logs. actual replacement logic + testing is next :)

* test suite built, and fully passing. made consle log edits too.

* added more replacement rules, but figuring out why they arent being implemented by my code.

* cleaning up test suite to not break when there are 0 rules; test is commited with 1 local rule. not sure if that rule is going to copy over when i merge.

* add: basic ui replacement menu

* add: frontend menu ui to annotation settings
- create replacementoptions file for 4 fix options: fix once, fix in library, fix in book, fix in library
-integrate with annotator.tsx
only frontend changes, but initialzied in backend

* add: delete global option and click gear option to get rid of menu

* docs: add test cases for replacementoptions file

* feat(replacement): modified ViewSettings interface and added Replacement type

feat(replacement): modified viewsettings interface and added ReplacementRulesConfig

* feat(replacement): Add text field, case sensitivity checkbox, and confirmation dialog to ReplacementOptions

- Add text input field for replacement text with placeholder
- Add 'Case Sensitive' checkbox (default: unchecked/case-insensitive)
- Implement two-step confirmation flow with Back/Confirm buttons
- Show preview of original text, replacement text, scope, and case sensitivity
- Disable scope buttons until replacement text is entered
- Display truncated preview for long selected text (>50 chars)
- Export ReplacementConfig type for use in parent components

* feat(replacement): Add 30-word limit and integrate new ReplacementOptions component

- Add MAX_REPLACEMENT_WORDS constant (30 words)
- Add getWordCount() utility function for word counting
- Show warning toast when word limit exceeded on Text Replacement click
- Replace old fix handlers with single handleReplacementConfirm()
- Integrate with new ReplacementConfig (replacementText, caseSensitive, scope)
- Display success toast with scope and case sensitivity info on confirm

* fix(build): Add ReplacementMenu placeholder component

- Create placeholder component to fix missing import error in reader/page.tsx
- Component returns null for now, to be implemented with global replacement rules

* test(replacement): Add comprehensive tests for ReplacementOptions and word limit

ReplacementOptions.test.tsx:
- Test rendering of text input, checkbox, and scope buttons
- Test case sensitivity checkbox toggle and state
- Test disabled buttons when no replacement text entered
- Test confirmation dialog flow and Back/Confirm buttons
- Test click outside and Cancel button behavior
- Test full replacement flow with all options

wordLimit.test.ts:
- Test word counting with various inputs (spaces, newlines, unicode)
- Test 30-word limit boundary conditions
- Test case-sensitive vs case-insensitive matching logic
- Test edge cases (empty string, long words, punctuation)

* refactor: removed unused initial definition of Replacement

* feat: added replacement rules window in bookmenu

* test: added tests to verify the replacement rules window renders book and global replacement rules, and it opens when bookmenu item is clicked

* feat: added Replacement tab in SettingsDialog, displays global rules

* fix: added single rules section to ReplacementRulesWindow

* refactor: created ReplacementPanel and edited style of inputs

* feat(replacement): connected front-end to functions. todo: fix the automatic reload functionality.

* fix(replacement): simplified re-rendering logic, doesn't fail on epubs anymore.

* test: add integration tests for text replacement functionality

* fix(replacement): added null checks to some unsafe calls in integration tests

* fix(replacements): added non-null assertion operator for a previously initialized variable

* feat: disable the edit feature for selected phrase

* refactor: use toast instead of banner for confirmation msg

* feat: automatically reload the page to apply changes

* feat: disable global rule for book if deleted in book view

* fix(replacement): Improve popup positioning and eliminate ghost animation

- Add viewport boundary detection to keep popup within visible area
- Calculate position only once on mount to prevent jumping when other UI appears
- Use visibility: hidden until position is calculated to eliminate ghost animation
- Add max-height with overflow-y: auto for scrollable content
- Popup now appears directly in correct position without two-step animation

* fix: only allow replacement for epubs, remove replacement rendering for non-epubs, add test cases

* fix: add logic for grayed out button for non-epubs

* fix: resolve all TypeScript/ESLint linting errors

- Fix prefer-const error in ReplacementOptions.tsx
- Fix set-state-in-effect error in ReplacementRulesWindow.tsx (use lazy initializer)
- Replace all @typescript-eslint/no-explicit-any with proper types (ReplacementRule, unknown, etc.)
- Fix unused error variables in replacement.ts (prefix with _)
- Remove unused eslint-disable directives
- Add missing ReplacementRule import in ReplacementPanel.tsx

* fix: add localStorage mock to vitest setup

- Fixes test failures in ReplacementRulesWindow and SettingsDialog tests
- localStorage mock ensures all Storage API methods are available in test environment

* fix: implement single-instance replacement with persistence

- Add sectionHref to TransformContext for section tracking
- Add singleInstance, sectionHref, occurrenceIndex fields to ReplacementRule
- Pass section name from FoliateViewer to transformer context
- Switch transformer from DOM-based to string-based replacement
- Handle single-instance rules with section matching and occurrence tracking
- Update Annotator to track occurrence index and apply direct DOM changes
- Persist single-instance rules for refresh survival

Single-instance replacements now:
1. Apply immediately via direct DOM modification
2. Store occurrence index and section for precise targeting
3. Persist across page refreshes

* fix: allow multiple single-instance replacements for same word

Single-instance rules now always create new entries instead of merging.
This fixes the issue where replacing multiple occurrences of the same
word would overwrite previous rules.

The transformer applies rules in sequence, so each rule targets
occurrence index 0 of the current (modified) string, allowing
cascading replacements to work correctly after refresh.

* fix: prevent cascading replacements and add wholeWord support

- Add wholeWord field to ReplacementRule for word boundary matching
- Track replaced regions to prevent replacement text from being re-matched
- Fix cascading replacement issue where replacement text was matched again
- Apply replacements from right to left to preserve positions
- Support whole word matching with \b boundaries for both single-instance and regular rules

* Fix whole-word matching for replacement rules

- Auto-enforce whole-word matching for simple word patterns (letters only)
- Add HTML tag boundary checks to prevent matching across tags
- Add double-check validation for whole-word matches
- Prevent matching 'and' inside words like 'England', 'stand', 'understand'
- Add comprehensive logging for debugging replacement issues

* refactor: refactored replacement logic for case sensitivity and word boundaries

* test: added tests for scope precedence and case sensitivity across scopes

* refactor: removed unnecessary code from testing

* feat: able to display, edit, and delete single-instance rules in book settings

* fix: connected case sensitive checkbox to backend, fixed merge and delete logic

* test: updated test cases to reflect changes on case sensitivity and rules rendering

* test: modified ReplacementOptions test to remove unnecessary case sensitive check from merge

* fix: resolve ESLint and TypeScript build errors

- Fix all remaining @typescript-eslint/no-explicit-any errors in test files
- Fix unused error variables in replacement.ts (prefix with _)
- Fix TypeScript error in ReplacementRulesWindow.tsx (move @ts-ignore to correct location)
- All ESLint checks now pass
- Web and Tauri builds compile successfully

* fix: update tauri-utils version to 2.8.1 to resolve duplicate symbol error

- Update local tauri-utils version from 2.8.0 to 2.8.1 to match crates.io version
- Fixes duplicate symbol __TAURI_BUNDLE_TYPE linker error
- Ensures all dependencies use the same tauri-utils version

* fix: use local tauri path directly to resolve version conflicts

- Change tauri dependency to use local path instead of version requirement
- This ensures all dependencies use the same local tauri version (2.9.3)
- Fixes 'links = Tauri' conflict error in Rust linting
- The patch.crates-io should still work for transitive dependencies

* fix: use version requirement with patch for tauri dependency

- Revert to using version requirement '2' instead of direct path
- Rely on [patch.crates-io] to use local tauri version
- Remove Cargo.lock to force fresh dependency resolution
- This should resolve the 'links = Tauri' conflict by ensuring
  all tauri dependencies (direct and transitive) use the patched version

* fix: remove plugin patches that cause resolution errors

- Remove all tauri-plugin git patches from [patch.crates-io]
- Keep only tauri, tauri-utils, and tauri-build patches
- Plugins from crates.io will use the patched tauri via transitive dependencies
- Fixes error: patch for tauri-plugin-oauth failed to resolve

* fix: add tauri-plugin to workspace and patch to resolve duplicate symbol error

- Add packages/tauri/crates/tauri-plugin to workspace members
- Add tauri-plugin patch to [patch.crates-io]
- This ensures all tauri dependencies use local versions
- Fixes duplicate symbol __TAURI_BUNDLE_TYPE linking error

* chore: restore Cargo.lock from upstream

- Restore the original Cargo.lock from readest/readest main branch
- This ensures reproducible builds and matches upstream
- The lock file will be updated by cargo when dependencies change

* fix: resolve TypeScript errors in test files

- Fix ReplacementOptions.test.tsx: add optional chaining for possibly undefined values
- Fix ReplacementRulesWindow.test.tsx: use proper type assertions for store setState calls
- Use (store.setState as unknown as (state: unknown) => void) pattern for partial state updates

* fix: allow selections with boundary punctuation and fix pattern matching for punctuation

- Updated isWholeWord() to explicitly allow selections that start or end with punctuation (e.g., 'tis, off;, look,)
- Fixed normalizePattern() to handle patterns with leading/trailing punctuation correctly
- Word boundaries are now only added around the word part, not the punctuation
- Fixes issue where replacements like 'scholar;' were not matching correctly

* fix: prevent race condition when deleting replacement rules rapidly

- Add isReloading state to track ongoing delete/edit operations
- Prevent multiple rapid deletions that cause runtime errors during page reload
- Show warning toast when user tries to delete while reload is in progress
- Add finally blocks to ensure isReloading is always reset
- This prevents the 'book doesn't finish rerendering' error

* fix: escape HTML entities in replacement text to preserve angle brackets

- Added escapeHtmlEntities() function to escape HTML special characters
- Apply HTML escaping to replacement text in both multi and single-instance replacements
- Fixes issue where replacement text like '<<AND>>' was being interpreted as HTML tags
- Angle brackets and other HTML entities are now properly escaped and displayed correctly

* fix: revert Tauri backend changes and resolve package.json conflict

- Revert Cargo.toml and src-tauri/Cargo.toml to match upstream/main
- Resolve @tauri-apps/cli version conflict (2.9.5 -> 2.9.6)
- These changes are not related to the replacement feature implementation

* fix: update pnpm-lock.yaml to match @tauri-apps/cli 2.9.6

* removed useless tests and backend tests from ReplacementOptions integration testing suite

* chore: revert foliate-js submodule to match readest/readest main

* fix: refactored display dialog logic to match other dialogs

* fix: enabled global rule deletion in book menu

* fix: removed ReplacementPanel from library settings

* fix: deleted SettingsDialog.replacement.test.tsx since we no longer need to display replacements in library settings

* fix: removed text replacement tab from settings dialog

* fix: applied prettier code formatter to replacement rules window

* fix: refactored wordLimit logic into a separate util file

* fix: removed additional pr description

* style: format code with prettier

* chore: fix formatting and remove unused file listed by chrox

* chore: format all changed files from pr 2693 and revert pnpm-lock

* fix: fixed inconsistencies from rebase

* refactor: removed unused code

* refactor: removed unintentional formatting changes

* fix: set upstream for packages/tauri-plugins to the readest branch

* fix: used original Cargo.lock file

* fix: got Cargo.lock from upstream

* fix: fetched SettingsDialog from upstream main

* fix: pointed tauri-plugins to the same commit as upstream

* chore: remove unnecssary comments from replacement.ts

* chore: fixed more unnecessary comments

---------

Co-authored-by: fatbiscuit247 <fatbiscuit247@github.com>
Co-authored-by: joon <your.email@example.com>
Co-authored-by: jarchenn <jerryc2@andrew.cmu.edu>
Co-authored-by: joon0429 <68578999+joon0429@users.noreply.github.com>
Co-authored-by: Jerry Chen <50bmg@Jerrys-MacBook-Pro-9.local>
Co-authored-by: Alicia Chen <aliciach@andrew.cmu.edu>
Co-authored-by: Jerry Chen <50bmg@MacBook-Pro-7.local>
Co-authored-by: Jerry Chen <50bmg@macbook-pro-158.wifi.local.cmu.edu>
Co-authored-by: fatbiscuit247 <136537548+fatbiscuit247@users.noreply.github.com>
2025-12-17 10:06:59 +08:00
Huang Xin fe50b513b3 fix(layout): line clamp opds url, closes #2726 (#2731) 2025-12-16 17:03:15 +01:00
Huang Xin 17c7fa8f41 fix: make sidebar and notebook pin states persist after refresh (#2730) 2025-12-16 16:16:21 +01:00
Huang Xin 2533560d11 fix(layout): fix bleed layout for images (#2729) 2025-12-16 15:46:13 +01:00
Huang Xin 5850a16afd fix: add stats API and fix fd leak, closes #2323 (#2723) 2025-12-16 06:51:48 +01:00
Huang Xin 7063d62b13 fix(settings): screen brightness setting only applies to the reader page, closes #2717 (#2720) 2025-12-15 06:04:29 +01:00
dependabot[bot] 0bd6a217ae chore(deps): bump actions/cache from 4 to 5 in the github-actions group (#2719)
Bumps the github-actions group with 1 update: [actions/cache](https://github.com/actions/cache).


Updates `actions/cache` from 4 to 5
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 05:14:57 +01:00
Huang Xin b7df294d78 feat(bookshelf): add group books button in context menu, closes #2698 (#2718) 2025-12-15 05:02:52 +01:00
Huang Xin 5aa78f2554 fix(opds): expose X-Content-Length header for CORS requests (#2715) 2025-12-14 19:06:09 +01:00
Huang Xin e740571c33 feat(opds): instant search bar for opds catalog, closes #2707 (#2714) 2025-12-14 18:25:47 +01:00
Huang Xin e6d9913f4e fix(layout): make sure annotation popups can be accessible in some edge cases, closes #2704 (#2713) 2025-12-14 05:52:55 +01:00
Huang Xin 1869a863a3 fix(layout): fixed max inline width not applied for EPUBs, closes #2706 (#2711) 2025-12-13 18:52:26 +01:00
Huang Xin 524de92f5e feat(macOS): add open file global menu for macOS, closes #2692 (#2708) 2025-12-13 17:36:25 +01:00
Huang Xin c1530cc5c4 feat(iOS): support open file with Readest in Files App, closes #2334 (#2705) 2025-12-13 13:28:03 +01:00
Huang Xin 730fadb834 fix(web): fixed router glitches for library page after returned from reader (#2703) 2025-12-13 08:08:42 +01:00
Huang Xin 383e5c61b1 chore: bump next.js to version 16.0.10 (#2702) 2025-12-13 07:54:15 +01:00
Huang Xin 6d42086fa7 fix(layout): fixed the layout of the selector of the translator providers (#2701) 2025-12-13 05:14:12 +01:00
mikepmiller 5a20fae204 feat(ui): progress info with cycleable display modes (#2682)
* Hideable Progress View
* feat: cycle between progress info modes

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-12-12 08:19:07 +01:00
Huang Xin 34fd64c5c4 fix(sync): handle special characters in filenames when downloading (#2694) 2025-12-11 19:20:27 +01:00
Huang Xin 0874fb0764 chore: bump tauri to the latest dev branch (#2690) 2025-12-11 13:46:41 +01:00
Huang Xin e03ed5b604 fix(layout): fix responsive layout for footnote popup (#2688) 2025-12-11 10:15:56 +01:00
Huang Xin 41edc89ac7 fix(pwa): don't cache api requests and cache client-side navigation routes (#2687) 2025-12-11 07:30:19 +01:00
Huang Xin f0a470398d chore(pwa): more aggressive offline cache for the web version (#2686) 2025-12-11 05:24:45 +01:00
Huang Xin 51008d81fb fix(opds): select proper opds search link (#2683) 2025-12-10 19:56:27 +01:00
Huang Xin 9828904674 feat(opds): added books catalog from standardebooks.org (#2681) 2025-12-10 18:20:56 +01:00
Huang Xin 2670d835b3 fix(comic): fixed layout for comic books, closes #2672 (#2680) 2025-12-10 18:08:11 +01:00
Huang Xin 8b7bafc4b6 chore(koplugin): add version info in the meta file (#2679) 2025-12-10 16:52:28 +01:00
Huang Xin ca759e0246 fix(tts): avoid false default en language code for TTS (#2678) 2025-12-10 16:24:01 +01:00
Huang Xin 5141be1c3f fix(iap): don't initialize billing on Android without google play service, closes #2630 (#2677) 2025-12-10 15:34:23 +01:00
Huang Xin 669d3950e2 chore: repackaging readest koplugin for updater, closes #2669 (#2676) 2025-12-10 13:37:32 +01:00
Huang Xin b95895cecf compat(opds): fallback to Basic auth if no WWW-Authenticate challenge in the response headers, closes #2656 (#2673) 2025-12-10 09:57:44 +01:00
Huang Xin 80e11bb0ce refactor(layout): refactor page margins for pixel precision, closes #2652 (#2663) 2025-12-09 16:19:14 +01:00
Huang Xin de3a539621 fix(footnote): add custom attributes for footnote in sanitizer, closes #2651 (#2657) 2025-12-09 05:27:52 +01:00
jacobi petrucciani b425bfdc89 chore: add rust and node deps to the nix devshell (#2655) 2025-12-09 04:44:53 +01:00
Huang Xin 1d1fbdffdb fix(macOS): delay writing to clipboard to ensure it won't be overridden by system clipboard actions, closes #2647 (#2649) 2025-12-08 14:05:27 +01:00
Huang Xin 50cd7f80c6 feat: refresh account info after managing cloud storage (#2648) 2025-12-08 13:13:20 +01:00
Huang Xin 6eb7d91122 release: version 0.9.95 (#2646) 2025-12-08 08:59:21 +01:00
Huang Xin 1fb468b3a6 fix(epub): support SVG cover for ebooks from standardebooks.org (#2645) 2025-12-08 08:52:17 +01:00
Huang Xin 3c7d95cf10 fix(footnote): responsive popup size so that on small screen it won't overflow (#2644) 2025-12-08 07:40:30 +01:00
Huang Xin ba3f060cc4 feat: add support for importing from a directory recursively, closes #179 (#2642) 2025-12-08 07:16:57 +01:00
Huang Xin 11bc7497e8 feat: add support for renaming bookshelf groups (#2639) 2025-12-07 10:04:23 +01:00
Huang Xin fb5d149413 fix: enable shared-intent event listener only on Android for now (#2638) 2025-12-07 06:45:56 +01:00
Huang Xin 42b47d73b7 feat: support cloud storage management (#2636) 2025-12-06 20:25:40 +01:00
Huang Xin 00f36af03a feat(opds): add support to search in OPDS, closes #2598 (#2634) 2025-12-06 12:13:45 +01:00
Huang Xin b78466ca93 fix(opds): relax img-src CSP to support images served from arbitrary HTTP/HTTPS hosts and ports, closes #2631 (#2633) 2025-12-06 04:22:15 +01:00
Huang Xin 4e6f146b8f feat(android): support opening shared files from other apps, closes #2484 (#2628) 2025-12-05 18:13:06 +01:00
Huang Xin cbdd4940d0 fix(android): intercept back button press for Android 15+, closes #2454 (#2626) 2025-12-05 16:27:09 +01:00
Huang Xin d022cb984a chore: bump various dependencies (#2624) 2025-12-05 07:48:03 +01:00
Huang Xin 8de6fa267e fix(cache): invalidate config and doc cache, closes #2595 and closes #2572 (#2623) 2025-12-05 07:03:57 +01:00
Huang Xin b08b7de8e9 fix(tts): fixed highlighting of current sentence for native tts on Android, closes #2620 (#2621) 2025-12-05 04:05:18 +01:00
Huang Xin a232a39f0e fix(pdf): Fixed zoomed layout and hand tool event handling, closes #2596 (#2617) 2025-12-04 19:22:01 +01:00
Huang Xin fad7966fc4 fix(layout): auto two-column layout for unfolded screen, closes #2588 (#2615) 2025-12-04 06:56:23 +01:00
Huang Xin a1487fd60c fix: get rid of the context menu for touch screen or stylus device when selecting text, closes #2579 (#2614) 2025-12-04 06:04:06 +01:00
Huang Xin 9606e315d4 fix(layout): hide overflow of children elements in duokan bleed, closes #2597 (#2613) 2025-12-04 03:40:43 +01:00
Huang Xin 978673268b chore: bump next.js to version 16.0.7 (#2612) 2025-12-04 02:34:10 +01:00
Huang Xin 70158a7f15 refactor(opds): use catalog id instead of credentials in url params, closes #2599 (#2606) 2025-12-03 08:50:55 +01:00
Huang Xin 18d65a2c5b fix(annotator): don't copy selection to notebook with keyboard shortcut by default, closes #2603 (#2605) 2025-12-03 07:08:00 +01:00
Huang Xin 1b0c2afad7 fix(layout): fixed scrollable layout in the about readest window, closes #2593 (#2604) 2025-12-03 06:23:02 +01:00
Huang Xin cef444d374 fix: disable saving last book cover with playstore variant, closes #2600 (#2602) 2025-12-03 05:41:44 +01:00
Huang Xin 75f6efe27a compat(opds): add User-Agent header to fix downloads from Calibre Web OPDS (#2592) 2025-12-02 10:27:33 +01:00
Huang Xin 852f9f40ec chore: fix cross compiling of thumbnail extension (#2587) 2025-12-02 02:27:03 +08:00
Huang Xin b9dadc0f4f chore: update flathub metainfo (#2586) 2025-12-01 18:07:29 +01:00
Huang Xin d120cf6573 release: version 0.9.94 (#2585) 2025-12-01 17:46:33 +01:00
Huang Xin d2b3c165c7 fix(opds): use custom header for content length when streaming content (#2584) 2025-12-01 17:28:36 +01:00
Huang Xin 742f06ce05 fix(toc): scroll to current toc item and anchor in TTS mode, closes #2574 (#2583) 2025-12-01 15:50:46 +01:00
Huang Xin e28dabce65 fix(layout): refactor full height for edge to edge env and in browser env (#2582) 2025-12-01 13:48:14 +01:00
Huang Xin 33ef781e21 feat: also convert quotation marks between Chinese variants (#2578) 2025-12-01 09:27:22 +01:00
Huang Xin 02e885fbb7 fix(opds): workaround parsing of encoded params in proxied url in cloudflare (#2575) 2025-12-01 05:49:04 +01:00
Huang Xin 2ca3561093 feat(opds): support downloading ebooks from OPDS catalogs (#2571) 2025-11-30 21:22:54 +01:00
Huang Xin 97f021da87 fix(extensions): add missing tauri conf for windows build (#2563) 2025-11-28 05:56:45 +01:00
Huang Xin bd2b45e1c1 refactor(extensions): move windows-thumbnail to extensions (#2562) 2025-11-28 05:44:11 +01:00
AlI 2b6f7b71b0 feat(windows): Add explorer thumbnail registration and installer hook… (#2557)
* feat(windows): Add Windows Explorer thumbnail support for ebooks (closes #2534)

- Implement IThumbnailProvider COM handler for Windows Shell integration
- Support EPUB, MOBI, AZW, AZW3, KF8, FB2, CBZ, CBR formats
- Add cover extraction with Readest icon overlay
- Register thumbnail handler via NSIS installer hooks
- Only show thumbnails when Readest is the default app for the file type

* chore: clean up build script for thumbnail extension

---------

Co-authored-by: chrox <chrox.huang@gmail.com>
2025-11-27 21:31:52 +01:00
Huang Xin 0bad380a50 fix(layout): fixed navigation parameters not synced with settings (#2559) 2025-11-27 08:06:43 +01:00
Huang Xin ecc20e8521 feat: apply progress style to footerbar progress (#2556) 2025-11-26 16:58:26 +01:00
Huang Xin d5c813fac1 fix(layout): avoid cascading refresh when cleaning up query parameters (#2555) 2025-11-26 15:52:29 +01:00
Huang Xin d9b3757b1c fix(layout): fix layout for import book item in grid fit mode (#2554) 2025-11-26 14:49:07 +01:00
Huang Xin fd7f90236d compat(ios): avoid lookbehind assertions for iOS older than 16.4 (#2553) 2025-11-26 11:31:31 +01:00
Huang Xin df9d21393d fix(layout): layout of the grid columns setting (#2552) 2025-11-26 10:19:29 +01:00
Huang Xin 1f73f15ad8 feat: add view option to set cover image size in grid mode, closes #2545 (#2551) 2025-11-26 07:49:51 +01:00
Huang Xin ba2aa4bee6 fix(layout): skip applying safe area insets when the iframe content is reloaded (#2550) 2025-11-26 04:10:52 +01:00
Huang Xin f709a657fa compat(css): sanitize insane absolute position, closes #2547 (#2549) 2025-11-25 17:19:29 +01:00
Huang Xin 514780a572 feat(shortcut): add shortcuts for annotation tools, closes #2270 (#2548) 2025-11-25 16:10:18 +01:00
Huang Xin 0c51a625f3 i18n: add translations for Bahasa Melayu(ms) (#2543) 2025-11-25 10:35:29 +01:00
Huang Xin 6f8b2d1dc4 fix(android): support back action for grouping modal (#2542) 2025-11-25 10:10:56 +01:00
Huang Xin 0087ce2f19 feat: add option to clear custom fonts in Font Panel (#2541) 2025-11-25 09:19:24 +01:00
Huang Xin b98c2796c8 feat: add option to apply page margins in scrolled mode, closes #2014 (#2540) 2025-11-25 08:55:33 +01:00
Huang Xin 37d56b3205 fix(android): support back key in menu, dialog and alert widgets, closes #2454 (#2539) 2025-11-25 08:01:17 +01:00
Huang Xin 5a54c0fb60 compat(css): override blockquote bg color in dark mode, closes #2281 (#2538) 2025-11-25 04:22:02 +01:00
StepanSad 99b259836b Update Ukrainian translations for consistency (#2535) 2025-11-25 09:28:12 +08:00
Huang Xin a54daaaa90 feat(shortcut): add ctrl + mouse wheel to zoom in/out, closes #2011 (#2533) 2025-11-24 17:19:28 +01:00
Huang Xin fa66e6fca6 feat(pdf): add support for hand tool panning for PDFs, closes #2518 (#2532) 2025-11-24 14:37:52 +01:00
Huang Xin b7864dded2 fix(eink): adjust sidebar and notebook background color for eink, closes #2497 (#2529) 2025-11-24 09:56:26 +01:00
Huang Xin 72d9698f38 fix: prevent file corruption using a robust backup strategy, closes #2512 (#2528) 2025-11-24 08:58:42 +01:00
Huang Xin a7937cd657 fix(translator): resolve occasional translation failures when navigating to new chapters (#2527)
Closes #2451.
2025-11-24 07:47:03 +01:00
Huang Xin 998b14c5b0 fix(layout): avoid clipping text because of negative indent, closes #2498 (#2526) 2025-11-24 06:11:29 +01:00
dependabot[bot] bff9c2a770 chore(deps): bump actions/checkout in the github-actions group (#2525)
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 05:35:17 +01:00
Huang Xin b5acdffc87 fix(annotator): fixed layout shift when selecting text in paginated mode on Android (#2524) 2025-11-24 04:06:25 +01:00
Huang Xin 127609160c chore: add more test cases for simplecc (#2522) 2025-11-23 17:41:54 +01:00
Huang Xin 8f22a5c570 feat: select directory to save last book cover image (#2521) 2025-11-23 17:00:49 +01:00
Huang Xin c792c18e01 feat: support text conversion between simplifed and traditional Chinese, closes #2508 (#2520) 2025-11-23 09:56:12 +01:00
Huang Xin cd614e3845 feat(cjk): add an option to replace quotation marks in vertical layout for CJK languages (#2511) 2025-11-22 14:09:20 +01:00
Huang Xin 40673f9cb8 docs: update README and app metadata (#2509) 2025-11-22 07:08:07 +01:00
Huang Xin 911aa4c73d chore(flathub): verify the readest app on flathub (#2507) 2025-11-22 04:07:10 +01:00
Huang Xin 74b4cc2ceb chore(flathub): update oars content attribute (#2504) 2025-11-21 16:44:19 +01:00
Huang Xin c0c463977d fix: proper code indentation (#2503) 2025-11-21 16:24:45 +01:00
Huang Xin 273bcafe01 fix: resolve endless loading indicator (#2502) 2025-11-21 14:58:55 +01:00
Huang Xin 9028059919 chore: fix cf deploy scripts (#2501) 2025-11-21 13:03:56 +01:00
Huang Xin c86af457e7 chore: bump Next.js to 16.0.3 (#2496) 2025-11-21 12:49:36 +01:00
Huang Xin b8e979be55 fix(layout): fixed some rendering problems on Next 16 (#2495) 2025-11-21 08:23:42 +01:00
Huang Xin 8849c19e8e fix(flathub): fix releases notes (#2494) 2025-11-21 06:20:04 +01:00
Huang Xin f1b4d02323 chore: sync app metadata release notes (#2492) 2025-11-21 04:44:50 +01:00
Huang Xin 4aa8847037 chore: bump tauri to version 2.9.3 (#2488) 2025-11-20 14:18:27 +01:00
Huang Xin d2389400a9 fix(annotator): don't scroll page when annotator is shown in TTS mode, closes #2479 (#2487) 2025-11-20 13:24:58 +01:00
Huang Xin 721e70d027 release: version 0.9.93 (#2486) 2025-11-20 06:33:58 +01:00
Huang Xin 3c1a7eac86 fix(library): fixed occasional freeze when navigating back to the library (#2485)
Closes #2482.
2025-11-20 06:15:49 +01:00
Huang Xin f8e21dbd4c fix(sync): fixed sync issues affecting new accounts, closes #2481 (#2483) 2025-11-20 04:28:41 +01:00
Huang Xin d16a35d26f fix(layout): constrain image height within table cells in paginated mode (#2480)
Closes #2472.
2025-11-19 18:06:39 +01:00
Huang Xin f881caf794 chore(pwa): config workbox to skip precaching next.js internal files (#2478) 2025-11-19 14:38:04 +01:00
54wedge eb6fa276de fix(txt): register style.css to content.opf (#2476)
* fix(txt): register style.css to content.opf

* refactor: code styling

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-11-19 13:59:04 +01:00
Huang Xin e987c8b37a chore(pwa): get rid of public headers requests (#2477) 2025-11-19 13:31:21 +01:00
Huang Xin 26d76e27ac fix(txt): more tolerant encoding detection for utf-8 (#2475) 2025-11-19 07:47:10 +01:00
Huang Xin 975549fca0 fix(font): avoid overriding monospace fonts for code blocks, closes #1805 (#2474) 2025-11-19 06:57:45 +01:00
Huang Xin 9a6bed52dd fix(sync): propagate book delete status to other devices (#2473) 2025-11-19 05:47:59 +01:00
Huang Xin efd9ad12a9 release: version 0.9.92 (#2469) 2025-11-18 15:15:27 +01:00
Huang Xin 93a71a0fd0 fix(bookshelf): ensure 'select all' only targets books in the active group (#2468) 2025-11-18 14:34:32 +01:00
Huang Xin d373d7ac28 fix(txt): handle chapter title patterns (#2467) 2025-11-18 14:09:03 +01:00
Huang Xin e0e991b599 fix(kosync): proxy kosync request only for the web app, closes #2440 (#2466) 2025-11-18 13:44:30 +01:00
Huang Xin 6d5b16ea8b fix(iap): open external app for payment (#2465) 2025-11-18 12:07:43 +01:00
Huang Xin bfac67d3f0 fix: ger rid of the AbortSignal polyfill (#2463) 2025-11-18 09:10:53 +01:00
Huang Xin 0fd316d775 fix(sync): retry sync books for previous failed sync, closes #2441 (#2462) 2025-11-17 18:52:48 +01:00
Huang Xin c42fcf9ac4 fix: save reading progress when closing app directly in reader page, closes #2346 (#2461) 2025-11-17 16:35:56 +01:00
Huang Xin 04ade02a06 fix(layout): enlarge clickable area for the close button in the reader page (#2459) 2025-11-17 15:22:05 +01:00
Huang Xin 8ee53d3367 fix(mobi): properly handle empty fragments for MOBI (#2456) 2025-11-17 05:09:09 +01:00
Huang Xin 42111945b8 fix(layout): scale table to fit within column constraints, closes #2445 (#2455) 2025-11-17 04:52:23 +01:00
Huang Xin 6fde157047 feat(bookshelf): support nested groups in the bookshelf, closes #568 (#2449) 2025-11-16 13:59:37 +01:00
Huang Xin 65ec5c9842 fix(library): avoid invalid regular expression in library search (#2439) 2025-11-16 14:07:29 +08:00
Huang Xin a6444b5b33 feat: supported updating email address for Readest account (#2437) 2025-11-12 19:03:02 +01:00
Huang Xin c7238cb04c fix(css): overriding book color for more semantic tags, closes #2433 (#2436) 2025-11-11 19:44:13 +01:00
Huang Xin 366e5fafad fix: fixed multiple windows are opened when opening with readest, closes #2429 (#2435) 2025-11-11 19:36:28 +01:00
Huang Xin fb5710c134 fix(pdf): disabled pagination with swipe gesture below minimum velocity for PDFs, closes #2428 (#2434) 2025-11-11 18:20:45 +01:00
ByteFlow c4d9652335 fix(annotator): enhance PDF context menu for translation and improve touch handling (#2430)
* fix(annotator): enhance PDF context menu for translation and improve touch handling

* feat(annotator, shortcuts): add keyboard shortcuts for selection actions

* feat(annotator): reposition popups on scroll to enhance user experience

* feat(annotator): disable currently unsupported annotator functions for PDFs

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-11-11 15:10:44 +01:00
Huang Xin df6027cf9f fix(eink): avoid gray color in E-Ink mode (#2427) 2025-11-09 19:17:35 +01:00
Huang Xin e3f7abf7f1 fix(tts): fixed incorrectly selected voices, closes #2386 (#2426) 2025-11-09 19:11:12 +01:00
Huang Xin c539917d7e compat(footnote): support more footnote formats (#2425) 2025-11-09 18:07:39 +01:00
Huang Xin 5eb870c978 fix(layout): don't hide horizontal scrollbar, closes #2418 (#2424) 2025-11-09 17:03:24 +01:00
Huang Xin b075c46ba3 compat(sync): compatibility for kosync server implementations that do not return timestamp (#2422) 2025-11-09 14:42:07 +01:00
Huang Xin 4b6c7776f5 fix(eink): no shade in eink mode (#2421) 2025-11-09 14:34:26 +01:00
Huang Xin 745a14195d fix(layout): fixed header bar z index (#2413) 2025-11-06 10:56:28 +01:00
Huang Xin fb0f660eaf fix(android): fixed back gesture to close config panel, closes #2406 (#2411) 2025-11-05 22:45:13 +01:00
Huang Xin 04a3030b79 fix(metadata): fixed changing cover image in Readest apps, closes #2402 (#2410) 2025-11-05 20:43:42 +01:00
Huang Xin 5a3114de48 fix(android): get brightness of the current window on Android, closes #2389 (#2409) 2025-11-05 19:36:45 +01:00
Huang Xin b808fc5954 fix: default to not override book color for PDF, closes #2397 (#2404) 2025-11-04 18:46:37 +01:00
Huang Xin 0ec4e37c13 fix(css): support style transformer for inline css (#2403)
* fix(css): support style transformer for inline css

* fix(eink): bold text for current chapter in the TOC, closes #2401
2025-11-04 18:36:46 +01:00
Huang Xin 9d301631ca fix(layout): restrict image container within column boundaries, closes #2390 (#2398) 2025-11-03 16:35:08 +01:00
Huang Xin ec7145bb01 fix(upload): sanitize filenames before uploading to cloud bucket (#2396) 2025-11-03 11:17:24 +01:00
Huang Xin f79d84b5fa fix(eink): more readablility for E-Ink mode on the library page, closes #2364 (#2395)
This also closes #2391 and closes #2394.
2025-11-03 09:23:35 +01:00
Huang Xin d00f1e0def feat(import): import files directly into the current book group (#2393) 2025-11-03 05:47:26 +01:00
Huang Xin 637a813732 fix(settings): don't show system fonts on Android, closes #2381 (#2388) 2025-11-02 09:49:25 +01:00
Huang Xin 4f33c9280b fix(layout): fine tuning of column width in scrolled mode and vertical mode, closes #2383 (#2387) 2025-11-02 09:34:57 +01:00
Huang Xin d54c752637 fix(koplugin): properly refresh access token (#2384) 2025-11-02 04:50:54 +01:00
Huang Xin 984d5d198d fix(css): avoid overriding table background color by default, closes #2377 (#2379) 2025-11-01 15:09:46 +01:00
Huang Xin 2568778a87 feat(layout): support for duokan bleed layout, closes #2374 (#2378) 2025-11-01 14:26:48 +01:00
Huang Xin 0d805a64f6 compat: polyfill AbortController/AbortSignal on older browsers (#2371) 2025-10-31 06:15:59 +01:00
Huang Xin 066d1c5b1e fix(import): resolve import failures for certain EPUB files, closes #230 (#2370)
If the publisher has already been parsed, don’t remap it from the author or contributor fields again.
This prevents failures when parsing metadata like <dc:creator opf:role="pbl" />.
2025-10-31 05:12:24 +01:00
Huang Xin cdc1950c3a fix(layout): various fixes on the book and reader styles and layouts, closes #2368 (#2369) 2025-10-30 19:34:55 +01:00
Huang Xin 7142874513 fix(ui): display exact storage capacity in the user profile (#2366) 2025-10-30 11:50:39 +01:00
Huang Xin 409c2f62be release: version 0.9.91 (#2362) 2025-10-29 16:37:43 +01:00
Huang Xin 82922c5053 feat(eink): add an option to save last book cover on Android, closes #1414 (#2361) 2025-10-29 16:15:08 +01:00
Huang Xin 9c5bcb13e2 feat(plan): show life-time plan name in user profile (#2360) 2025-10-29 15:36:12 +01:00
Huang Xin 1d87dcdb7f feat: add options to customize the style of highlighted text of current sentence of TTS (#2358) 2025-10-29 10:17:36 +01:00
Huang Xin c7ba44a91e eink: disable all shadows in E-Ink mode (#2354) 2025-10-29 06:46:17 +01:00
Huang Xin 19b79c5b35 fix(android): fixed Android launcher icon size on some Android systems (#2353) 2025-10-29 06:19:02 +01:00
Huang Xin 45216763e3 fix(compat): use xml serializer for sanitized doc for better compatibility (#2352) 2025-10-29 05:12:19 +01:00
Huang Xin 123293dc0e fix: fixed crash when switching allow script (#2351) 2025-10-29 03:17:17 +01:00
Huang Xin 78e61060d2 fix(tts): fixed listener of tts events (#2349) 2025-10-28 18:36:57 +01:00
Huang Xin dd5371d2fd release: version 0.9.90 (#2344) 2025-10-28 05:44:07 +01:00
Huang Xin da041d1f38 fix(ui): hover to display footer bar in non-maximized windows on desktop (#2343) 2025-10-28 05:30:41 +01:00
Huang Xin d01599a2b4 feat(security): sanitize XHTML safely to prevent XSS when scripts are disabled, closes #2316 (#2342) 2025-10-28 04:28:48 +01:00
Huang Xin e80a2268ac feat(ui): add non-linear scale to brightness slider for better low-value control (#2338)
Implement logarithmic mapping for screen brightness slider to improve
usability at low brightness levels where small percentage changes have
significant visual impact.
2025-10-27 13:45:43 +01:00
Huang Xin 3b86229c8f perf(sync): batched updating notes and books when syncing (#2337) 2025-10-27 13:37:04 +01:00
Huang Xin c4d498d183 perf: much faster sync of the whole library (#2336) 2025-10-27 05:33:12 +01:00
Huang Xin 9bc46914e2 feat(iap): support expanding cloud storage with IAP on iOS and Android (#2331) 2025-10-26 10:18:56 +01:00
AlI 75f982e677 i18n(fa): refactor Farsi translation (#2330)
Restructure the Farsi translation to align with the format and key organization used in other translation files. This improves consistency and maintainability.
2025-10-26 08:58:57 +01:00
AlI f58bfeb1d0 fix(layout): Fix popup menu for RTL languages (#2327) 2025-10-26 08:51:25 +08:00
AlI ebb077f6e0 i18n: add translations for Persian/Farsi(fa), closes #2321 (#2326) 2025-10-25 15:32:24 +02:00
Huang Xin fdf6908fc6 feat: expand cloud storage with one-time payment (#2325) 2025-10-25 11:46:51 +02:00
Huang Xin 7936660868 docs: add sponsor links in README (#2318) 2025-10-24 15:22:08 +02:00
Huang Xin 554dd3798f fix: more explanatory error message when importing books, closes #2309 (#2314) 2025-10-24 07:15:41 +02:00
Huang Xin 7f40d8e12c fix(eink): more readability for progress info and section info in E-Ink mode, closes #2311 (#2313) 2025-10-24 06:14:25 +02:00
Huang Xin 31d6f44ff5 fix(iOS): restore last page if app is terminated in the background (#2312) 2025-10-24 05:42:52 +02:00
Huang Xin 86efcde927 feat(tts): add an option to select target language for TTS on translated books (#2310) 2025-10-23 19:34:43 +02:00
Huang Xin 4acbc33762 fonts: add PT font families (#2308) 2025-10-23 16:05:28 +02:00
Huang Xin 7cd3ebfcba compat: support .fb.zip files as FBZ format (#2307)
Although .fb.zip is not an officially recognized extension, many FBZ files use this format, so it's now treated as FBZ for compatibility.
2025-10-23 15:38:44 +02:00
Huang Xin 55c97cab7e perf: improve smoothness of Arrow Up/Down scrolling, closes #2080 (#2306) 2025-10-23 15:32:51 +02:00
Huang Xin 5bde091704 feat(settings): add an option to click both sides of the screen to paginate forward, closes #1951 (#2305) 2025-10-23 13:57:03 +02:00
Huang Xin 70489b46a5 fix(search): correctly display results when searching from selected text (#2304) 2025-10-23 11:52:49 +02:00
Huang Xin d7e89cc01f fix(layout): responsive layout for the custom highlight colors options (#2303) 2025-10-23 11:51:31 +02:00
Huang Xin a1f6030e75 fix(iOS): detect and recover from WebContent process termination (#2302) 2025-10-23 10:37:07 +02:00
Huang Xin e7b2d8435e feat(eink): set underline text decoration for links in E-Ink mode, closes #2293 (#2299) 2025-10-22 18:52:30 +02:00
Huang Xin f890a9633b feat(settings): add an option to set auto screen brightness (#2297) 2025-10-22 18:45:51 +02:00
Huang Xin 5bdcd3124b chore: bump tauri to version 2.9.0 (#2296) 2025-10-22 17:51:35 +02:00
Huang Xin 752b3f8e4c chore: bump nextjs, opennextjs and supabasejs (#2295) 2025-10-22 16:19:06 +02:00
Huang Xin 001e836ae3 chore: bump eslint-config-next to version 16 (#2294) 2025-10-22 15:57:04 +02:00
Huang Xin 50d7f9a9dd feat(android): support custom data location on external sdcard (#2292) 2025-10-22 10:14:41 +02:00
Huang Xin 34a5e58872 feat: add keyboard shortcuts to go prev/next sections, closes #2287 (#2291) 2025-10-22 07:41:33 +02:00
Huang Xin 34fbea6a44 css: properly handle theme color in dark mode for code blocks, closes #2281 (#2290) 2025-10-22 06:56:53 +02:00
Huang Xin 8737535b90 feat: support Android IAP (#2286) 2025-10-21 18:24:50 +02:00
Huang Xin 28ef414c3d feat: supported footnotes for definition list, closes #2278 (#2279) 2025-10-20 10:38:46 +02:00
dependabot[bot] 16279949c1 chore(deps): bump actions/setup-node in the github-actions group (#2277) 2025-10-20 12:25:42 +08:00
Huang Xin 444e22dd0e chore: i18n for highlight color settings (#2275) 2025-10-19 18:59:26 +02:00
仿生猫梦见苦力怕 a231506713 fix(css): support at rules of CSS and fix CSS formatter (#2269)
* refactor: replace manual CSS validator with PostCSS

* Revert "refactor: replace manual CSS validator with PostCSS"

This reverts commit 609ed7dd5a50debcea0303cc1043440af9849ddc.

* fix: support at rules of CSS and fix CSS formatter

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-10-19 18:09:04 +02:00
airwish 5dcabba73c chore: add contribution settings (#2274) 2025-10-19 17:14:20 +02:00
AlI cd71c494da feat(settings): add custom highlight color picker (#2273)
Add ability to customize highlight colors with hex color picker. Users can now set custom colors for all five highlight styles (red, violet, blue, green, yellow) in the settings panel.

Fixes #2271
2025-10-19 17:03:59 +02:00
Huang Xin f66642b8ec tts: avoid using AnaNeural as default English voice (#2272) 2025-10-19 14:58:51 +02:00
Huang Xin 2283e1b0f2 fix(layout): fix inline image, closes #2263 (#2266) 2025-10-18 17:25:37 +02:00
Daniil Leontev e0eb725d8b fix: add more elements to color overrides (#2265) 2025-10-18 22:25:02 +08:00
Huang Xin 05e9549410 release: version 0.9.88 (#2258) 2025-10-17 18:06:00 +02:00
Huang Xin 35fbce3506 feat(settings): added an option to disable animation in E-Ink mode, closes #2253 (#2257) 2025-10-17 18:00:58 +02:00
Huang Xin c1d6825793 fix: more sensitive snap to paginate, closes #2252 (#2256) 2025-10-17 16:05:39 +02:00
Huang Xin ae6c6970b4 feat: localize number in progress info in vertical layout (#2255) 2025-10-17 12:17:36 +02:00
Huang Xin f8fef57cf3 fix(layout): overriding book layout no longer overrides explicit text alignment, closes #2249 (#2254) 2025-10-17 11:44:32 +02:00
Huang Xin 4dc191735d fix(layout): prevent TTS indicator from disappearing too quickly to open configuration panel, closes #2247 (#2248) 2025-10-16 16:49:05 +02:00
Huang Xin 4f11f437e1 release: version 0.9.87 (#2245) 2025-10-16 10:27:34 +02:00
Huang Xin 5773e31990 compat(tts): fix crash with TTS on some versions of Android systems (#2244) 2025-10-16 10:10:04 +02:00
Huang Xin 9dda5d4c88 fix(tts): scroll more accurately to the highlighted text in TTS when header/footer bars are shown (#2242) 2025-10-15 17:50:56 +02:00
Huang Xin 7f5b6959e1 font: update font LXGW WenKai to the latest version (#2240) 2025-10-15 15:17:53 +02:00
Huang Xin 126981d085 fix(theme): fixed auto theme mode for new reader window (#2238) 2025-10-15 14:36:02 +02:00
Huang Xin 854a578929 compat: support parsing more footnotes, closes #2234 (#2237) 2025-10-15 11:59:27 +02:00
Huang Xin 6dd0daa597 txt: add chapter title pattern, closes #2232 (#2233) 2025-10-14 18:01:23 +02:00
Huang Xin fd24a5e9ac release: version 0.9.86 (#2230) 2025-10-14 14:08:45 +02:00
Huang Xin 948b35f244 perf: support concurrent book uploading, closes #2208 (#2229) 2025-10-14 14:00:31 +02:00
Huang Xin 96cc182a8c feat: support overriding html language code with language code in metadata, closes #2222 (#2227) 2025-10-14 13:09:23 +02:00
Huang Xin e2291ed5b1 feat(koplugin): register sync actions in gesture manager closes #2224 (#2226) 2025-10-14 09:54:08 +02:00
Huang Xin 60ddb17547 feat: add support for per-book background image settings in addition to global settings, also closes #2223 (#2225) 2025-10-14 08:54:26 +02:00
Huang Xin 9a991a31ba fix: handle empty custom textures (#2221) 2025-10-13 20:08:22 +02:00
Huang Xin 6de10c6c3b release: version 0.9.85 (#2220) 2025-10-13 19:15:55 +02:00
Huang Xin c7d49c1504 fix: load custom texture before applying it (#2219) 2025-10-13 19:04:45 +02:00
Huang Xin c721bd4d97 chore: enable turbopack by default in development env (#2218) 2025-10-13 16:39:17 +02:00
Huang Xin 5b0a1968d8 chore: add readest.koplugin in the release workflow (#2217) 2025-10-13 16:26:11 +02:00
Huang Xin ad9064fa46 fix(toc): fixed issues of scroll to active items in unpinned sidebar, closes #2213 (#2216) 2025-10-13 15:29:51 +02:00
Huang Xin f1c92e5702 feat: support customizing background images, closes #2018 (#2214) 2025-10-13 14:04:13 +02:00
Huang Xin 92c1441922 translator: add translator target language of Persian, closes #2206 (#2212) 2025-10-12 13:53:23 +02:00
Huang Xin 3820950c7c fix: show only the filtered books in groups (#2209) 2025-10-12 11:38:47 +02:00
Huang Xin 08e558bd41 fix: actually allow script in the transform target, closes #2200 (#2203) 2025-10-11 12:59:55 +02:00
Huang Xin 00af4a3d60 layout: make TTS icon less distracting during read-aloud mode (#2198) 2025-10-10 19:14:57 +02:00
Huang Xin ada427b134 feat(settings): add settings to adjust screen brightness when reading, closes #1532 (#2197) 2025-10-10 19:02:35 +02:00
Huang Xin f696b9a573 fix: handle scrolling/panning in zoomed in PDFs, closes #2184 (#2194) 2025-10-10 07:56:41 +02:00
Huang Xin 195beeacac chore: don't init posthog if users opt-out the usage data telemetry, closes #2187 (#2192) 2025-10-10 07:03:49 +02:00
Huang Xin 5b23ed35b6 txt: properly detect chapters in TXT files with dot-number format, closes #2188 (#2191) 2025-10-10 06:45:50 +02:00
Huang Xin 42c8702704 fix(cbz): fix issue where CBZ files fail to reopen after being closed, closes #2183 (#2190) 2025-10-10 05:50:40 +02:00
Huang Xin ad81376da8 fix(css): auto height of inline images with object-fit style (#2189) 2025-10-10 04:10:05 +02:00
Huang Xin 562fea3a36 fix(layout): fix inconsistent background color for unpinned drag bars (#2186) 2025-10-09 18:35:00 +02:00
Huang Xin b69d9ed69f tts: improve media session control compatibility across more Android systems (#2185) 2025-10-09 17:53:07 +02:00
Huang Xin ad6a21a68f refactor: split FooterBar into modular components for desktop and mobile (#2181) 2025-10-08 07:47:39 +02:00
Huang Xin 173aa0fcd1 layout: fix dragbar flickering when opening a book (#2177) 2025-10-06 05:52:36 +02:00
Huang Xin 788e08a75a shortcut: use shift+space to go backward in the reader page (#2176) 2025-10-06 05:31:16 +02:00
Huang Xin ec397a2daf fix: draw annotations of the current section on load, closes #2163 (#2174) 2025-10-05 17:47:34 +02:00
Huang Xin 2a5758fbc4 compat: disable customize root dir for macOS App Store builds (#2171)
CustomizeRootDir has a blocker on macOS App Store builds due to Security Scoped Resource restrictions.
See: https://github.com/tauri-apps/tauri/issues/3716
2025-10-05 08:28:45 +02:00
Huang Xin 562ccd4b9e feat: add keyboard shortcuts for toggling bookmarks/sidebar, importing books, closing window (#2170)
And make the shortcuts compatible with GNOME Human Interface Guidelines.
This closes #2079 and closes #2168.
2025-10-04 16:12:31 +02:00
make_aguess 4d577774f3 Adds adaptive icon for Android launcher (#2162)
Introduces an adaptive icon for the Android launcher, defining
separate layers for background, foreground, and monochrome
elements. Enhances visual consistency and supports adaptive
icon features on modern Android devices.
2025-10-04 09:00:33 +02:00
Huang Xin 4c10c16491 i18n: add translations for Swedish(sv) (#2159) 2025-10-02 14:25:01 +02:00
Huang Xin 7695f31a5a translator: translate to and from Norwegian Bokmål(nb) (#2158) 2025-10-02 14:09:01 +02:00
Huang Xin 06b27f8d39 chore: fix portable exe build for Windows (#2156) 2025-10-02 00:11:21 +08:00
Huang Xin e1691661d9 release: version 0.9.82 (#2155) 2025-10-01 16:45:01 +02:00
Huang Xin bc8e419d51 compat(koplugin): make meta_hash extraction more robust for calibre conversions and metadata edits, fixes #1838 (#2154) 2025-10-01 16:38:29 +02:00
make_aguess ccad1ca0d9 Add support for mono theme (#2122) (#2153) 2025-10-01 15:30:09 +02:00
Huang Xin 75c315fca8 fix(koplugin): only prompt network connection during interactive push progress, closes #2137 (#2152) 2025-10-01 14:57:58 +02:00
Huang Xin bdef593cdd feat: support global settings from library menu, closes #2140 (#2151) 2025-10-01 09:59:37 +02:00
Huang Xin d8943fc0c5 compat: normalize OKLCH color syntax for older iOS Safari, closes #990 (#2150) 2025-10-01 07:59:45 +02:00
Huang Xin cdd274e5ca compat: add support for WebView down to version 92, closes #2139 (#2145) 2025-09-30 19:14:35 +02:00
Huang Xin 2230741779 fix(i18n): apply system language on app start, closes #2141 (#2144) 2025-09-30 10:11:18 +02:00
Huang Xin 0e6950a60f i18n: localization for notification title and text (#2143) 2025-09-30 10:03:33 +02:00
Huang Xin 1d4541e353 feat: request manage external storage permission when changing data directory to sdcard root on Android (#2142) 2025-09-30 08:59:16 +02:00
Huang Xin 0a1e0212e2 feat: supported background TTS with media session controls, closes #2099 and closes #964 (#2138) 2025-09-29 19:45:17 +02:00
Huang Xin 25b44176b9 fix(tts): parse default language in ssml without translated text (#2135) 2025-09-27 17:52:54 +02:00
Huang Xin e1deff341d feat: supported changing data location on Android (#2131) 2025-09-26 17:32:16 +02:00
Huang Xin 3fc4c05e50 feat: build portable Windows binaries with app data kept within the executable directory (#2126) 2025-09-26 11:23:55 +02:00
Huang Xin 1843a74dbb feat: supported changing data location on desktop platforms, closes #2047 and closes #478 (#2125) 2025-09-26 10:22:41 +02:00
Huang Xin 9aa6a8e6b9 chore: bump tauri to the latest version (#2117) 2025-09-25 09:32:55 +02:00
Huang Xin 1de89069ce fix: handle pointer events for window dragging on touch screen Windows, closes #2010 (#2116)
* fix: handle pointer events for window dragging on touch screen Windows, closes #2010

* chore: fix rust-lint
2025-09-25 06:41:08 +02:00
Huang Xin 1e6525d085 fix(sync): handle incomplete config data from koreader (#2115) 2025-09-25 11:49:43 +08:00
Huang Xin d9d71b7d38 fix(css): overriding hard-coded font weight (#2113) 2025-09-24 17:03:17 +02:00
Huang Xin e85dec2b49 fix(sync): force a full sync after a certain period, closes #2111 (#2112) 2025-09-24 16:52:17 +02:00
Huang Xin c0f77b3368 fix(tts): abortable prefetch of tts data, closes #2037 (#2110) 2025-09-24 12:19:07 +02:00
Huang Xin 8c9855d167 fix(layout): avoid changing the safe area insets when virtual keyboard pops up on Android, closes #2105 (#2108) 2025-09-24 07:28:59 +02:00
Huang Xin 7c12bc8595 fix(mobi): fixed footnotes parsing for some MOBI/AZW files (#2106) 2025-09-23 08:53:43 +02:00
Huang Xin 5102f6b0ff fix(tts): handle und language code, closes #2100 (#2102) 2025-09-22 18:15:28 +02:00
Huang Xin dd40b9bae0 fix(layout): adjust font size instead of zooming HTML, closes #2088 (#2101)
Prevents issues with zoom handling in WebKit-based browsers such as Safari and WebKitGTK.
2025-09-22 17:43:22 +02:00
Huang Xin 98b4026990 fix(layout): scrollable book view and about window, closes #2090 (#2098) 2025-09-22 13:44:54 +02:00
Huang Xin b0640ba55b fix(fonts): higher priority for CJK fonts so that it can override system CJK glyphs (#2093) 2025-09-21 08:22:49 +02:00
Huang Xin c9a1557674 refactor: support custom root dir for readest file system (#2092) 2025-09-21 07:59:27 +02:00
Huang Xin 855f98722c tts: add more languages for edge tts (#2089) 2025-09-20 01:58:11 +02:00
Huang Xin 21a82b70c7 fix(a11y): better contrast for disabled buttons, closes #2083 (#2084) 2025-09-19 13:40:45 +02:00
Huang Xin 519e222883 release(hotfix): version 0.9.81 (#2082) 2025-09-19 13:20:48 +02:00
Huang Xin 488a242787 css: default to lower font-family specificity than the styles defined inside the ebook, closes #2070 (#2081) 2025-09-19 13:10:37 +02:00
StepanSad 523a03d212 Update translation.json (#2078) 2025-09-19 12:04:22 +02:00
Huang Xin d49f3442e8 fix(layout): scroll in the dropdown menu in landscape mode, closes #2072 (#2076) 2025-09-19 11:50:03 +02:00
Huang Xin 48dc570809 fix: handle invalid bookkey for viewState, closes #2073 (#2074) 2025-09-19 11:09:32 +02:00
Huang Xin 509320813f tts: support media session in desktop apps (#2071) 2025-09-19 10:22:39 +02:00
Huang Xin 54d7e73acb fix: disable swipe up to toggle action bar for PDF zoomed in (#2068) 2025-09-18 19:46:47 +02:00
Huang Xin 1bc0eb3a4b release: version 0.9.80 (#2067) 2025-09-18 18:45:12 +02:00
Huang Xin c0bf2d40dd fix: jump to current item in virtualized TOC list, closes #2055 (#2066) 2025-09-18 18:38:09 +02:00
Huang Xin e30a39f9cb fix(config): prevent occasional errors when saving progress and configs (#2065) 2025-09-18 16:56:44 +02:00
Huang Xin 9727e4e9b8 fix(metadata): handle invalid language code and title when importing, closes #2056 and closes #2058 (#2064) 2025-09-18 16:47:02 +02:00
Huang Xin 3380912cdb feat(kosync): use metadata hash to aggregate different versions of the same book (#2063) 2025-09-18 14:51:26 +02:00
Huang Xin 91a5454b46 feat(sync): aggregate books with metadata hash for progress and annotation sync (#2062) 2025-09-18 14:05:16 +02:00
Huang Xin e0c5acf4c8 chore: check file status before deleting cloud files (#2053) 2025-09-17 04:54:32 +02:00
Huang Xin 7e062be0d0 doc: update accessibility support in README (#2051) 2025-09-16 18:06:10 +02:00
Huang Xin b23876c2b9 a11y: support NVDA screen reader on Windows and Orca screen reader on Linux (#2050) 2025-09-16 17:38:21 +02:00
Huang Xin e9a152683e fix(layout): show focus ring only for keyboard navigation (#2046) 2025-09-15 21:13:52 +02:00
Huang Xin 34f1af727f a11y: accessibility for mobile platforms (#2044) 2025-09-15 18:45:45 +02:00
Huang Xin dfc24f3803 fix(layout): fix break word for titles in book detail, closes #2039 (#2043) 2025-09-15 09:21:35 +02:00
Huang Xin ec233f7b37 fix(sync): resolve issue where invalid tokens were occasionally used with the storage API (#2041) 2025-09-14 22:08:22 +02:00
Huang Xin bb34b1ba59 a11y: add screen reader support (#2040)
Tested with VoiceOver on iOS and macOS
2025-09-14 22:00:42 +02:00
Daniil Leontev b1fb477359 fb2: respect elements nested in stanza (#2038)
Updates foliate-js submodule to include necessary changes. Fixes #2027
2025-09-14 17:03:53 +02:00
StepanSad 3c877a19fc Update translation.json (#2032) 2025-09-14 08:49:02 +08:00
Huang Xin b47baa6b74 fix: add delete confirmation for book deletion from contextmenu, closes #2013 (#2029) 2025-09-12 18:27:07 +02:00
Huang Xin 14c85cbadf feat(metadata): add an option to remove cover image, closes #2020 (#2028) 2025-09-12 17:10:25 +02:00
Huang Xin a88b9139f8 fix: occasionally failed double click detection on the header bar on Windows, closes #2015 (#2026) 2025-09-12 13:36:56 +02:00
Huang Xin 251a4b52c0 fix: support dragging window on touch screen, closes #2010 (#2025) 2025-09-12 11:43:49 +02:00
Huang Xin 1aaeaf5ebe feat: add support links in the about window (#2024) 2025-09-12 08:03:35 +02:00
Huang Xin 9fd152d727 refactor(a11y): add basic lint for accessibility (#2021) 2025-09-11 18:57:04 +02:00
Huang Xin 2571ceede4 fix: also apply zoom shortcuts to PDFs (#2016) 2025-09-10 17:32:23 +02:00
Huang Xin 932cfa3b9f feat: show groups in list mode in the library page, closes #978 (#2009) 2025-09-09 18:18:54 +02:00
Huang Xin 01fde8573c fonts: support variable fonts when importing ttf/otf font files, closes #2003 (#2007) 2025-09-09 11:25:27 +02:00
Huang Xin d95656b37b fix(tts): compensate audio fade-in for resumed play on iOS and macOS, closes #2005 (#2006) 2025-09-09 08:29:39 +02:00
Huang Xin 210eda0340 fix: pagination with volume keys now has right direction for RTL books, closes #1996 (#2004) 2025-09-09 05:36:45 +02:00
Huang Xin 0d8b877d73 fix: don't show rounded window in maximized or fullscreen mode on (#2001)
Linux, closes #1998
2025-09-08 19:32:15 +02:00
dependabot[bot] 79d39b2295 chore(deps): bump the github-actions group with 2 updates (#1999) 2025-09-08 12:44:45 +08:00
Huang Xin e03b0af58a feat: swipe to paginate on fixed layout books, closes #1028 (#1995) 2025-09-07 16:14:34 +02:00
Huang Xin 71c2143cba fix: avoid pagination until book view is inited, closes #1983 (#1994) 2025-09-07 14:47:35 +02:00
Huang Xin 70a7f5be19 fix: use transparent background for rounded window on Linux, closes #1982 (#1991) 2025-09-07 10:38:27 +02:00
Huang Xin d2242423f5 fix: correctly parse filenames for woff/woff2 font files on Android, closes #1981 (#1990) 2025-09-07 07:04:48 +02:00
Huang Xin 782e9c8b20 fix: restore scale factor (zoom level) for PDFs, closes #1985 (#1989) 2025-09-07 06:12:57 +02:00
Huang Xin 55b2c678a4 fix(kosync): handle non-standard XPath syntax from Koreader, closes #1968 (#1988) 2025-09-07 06:05:27 +02:00
Huang Xin 48d754c184 fix(layout): prevent layout shift on Android browsers, closes #1979 (#1980) 2025-09-06 18:13:02 +02:00
Huang Xin ff0443ace7 compat: fixed zoom level handling on iOS and macOS, closes #1784 (#1978) 2025-09-06 16:07:06 +02:00
Huang Xin cc3cc58de0 release: version 0.9.78 (#1975) 2025-09-06 10:50:18 +02:00
Huang Xin 80d60266c2 settings: default to override background color in fixed layout documents (#1974) 2025-09-06 10:40:18 +02:00
54wedge f06cdb5899 txt: nest chapters inside volumes when converting to epub (#1972)
* txt: nest chapters inside volumes

* txt: readability

* txt: format
2025-09-06 10:28:26 +02:00
Huang Xin dfe68988aa fix(kosync): use 1-based indices in xpointer, closes #1968 (#1973) 2025-09-06 07:40:32 +02:00
Huang Xin d0264de3eb compat: more accessible iframes for PDFs, closes #1136 (#1971) 2025-09-05 18:56:15 +02:00
Huang Xin 77c4303938 feat(pdf): support setting zoom level, zoom mode and spread mode for PDF (#1969)
This should close #1717, close #1276, close #669.
2025-09-05 18:20:15 +02:00
Huang Xin 5724d2eeec feat(tts): support going previous/next by sentence in bottom TTS bar, closes #1816 (#1967) 2025-09-05 10:34:30 +02:00
54wedge 64007b1188 txt: improve zh chapter extraction (#1966)
* txt: improve zh chapter extraction

* txt: fix regexp

* txt: one more keyword
2025-09-05 10:31:26 +02:00
Huang Xin 50ee7bd8be doc: change badge colors for last commit and commit activity 2025-09-04 11:44:11 +02:00
Huang Xin 2bcbde4bf1 doc: fixed badge-language-coverage URL encoding 2025-09-04 11:39:27 +02:00
Huang Xin 99f75dd3b6 i18n: add Bengali(BN), Sinhala (SI) and Tamil (TA) translations (#1965) 2025-09-04 11:37:29 +02:00
Huang Xin 2b9132b4a8 feat(translator): preprocess some common mistranslated publishing terms (#1964) 2025-09-04 09:38:17 +02:00
Huang Xin 82782be16e fix: prevent layout shift when virtual keyboard pops up on Android, closes #1959 (#1963) 2025-09-04 08:04:51 +02:00
Huang Xin 7067129887 fix(tts): fixed headings cannot be highlighted in TTS (#1955) 2025-09-03 16:42:59 +02:00
Huang Xin 6e706ac8f7 feat: add inline editor for bookmarks in the sidebar, closes #1909 (#1954) 2025-09-03 11:06:35 +02:00
Huang Xin 39b902c927 epub: parse correct book front cover for some EPUBs, closes #1913 (#1953) 2025-09-03 07:50:26 +02:00
Huang Xin 94a9cd7c9d doc: update README and add link of readest subreddit (#1952) 2025-09-03 07:24:54 +02:00
Huang Xin 0dae7db140 fix: improved sensitivity of text selection with stylus, closes #706 (#1950) 2025-09-02 18:51:45 +02:00
Huang Xin 32954e025c fix(tts): media control in the lock screen and with airpods for iOS, closes #1407 (#1949) 2025-09-02 17:24:16 +02:00
Huang Xin 61dda9a517 feat: group custom fonts into families, closes #1934 (#1945) 2025-09-01 17:49:46 +02:00
Huang Xin 99a4cb50ac feat: add an option to show persistent TTS bar at the bottom, closes #1818 (#1944) 2025-09-01 14:23:28 +02:00
Huang Xin f4b00d6dec fix: get rid of invalid grid insets (#1943) 2025-09-01 07:05:48 +02:00
Huang Xin f69422a61c fix: conditional Back key interception on Android (#1942) 2025-09-01 06:16:31 +02:00
Huang Xin 7f4c157a90 chore: build with install package permission by default for Android (#1939) 2025-08-31 16:53:29 +02:00
Huang Xin 7d9724ff8b fix: close books with the system back key on Android, closes #1933 (#1938) 2025-08-31 10:15:28 +02:00
Huang Xin 06db7f36f8 refactor: rename ConfirmSyncDialog to KOSyncResolver (#1937) 2025-08-31 05:46:43 +02:00
Huang Xin f0c249bce2 release: version 0.9.76 (#1932) 2025-08-30 06:19:01 +02:00
Huang Xin e8a96fba95 compat: more compat with window insets on Android (#1931) 2025-08-30 06:18:06 +02:00
Huang Xin 92b01c40a0 layout: fix grouping modal not shown on Linux (#1930) 2025-08-30 05:28:02 +02:00
Huang Xin 6003eeadba compat: support more kosync server implementations, closes #1862 (#1929) 2025-08-30 04:54:31 +02:00
Huang Xin 856ed4d3b3 ux: add splash screen for iOS and Android and reduce flash when opening books (#1926) 2025-08-29 19:10:09 +02:00
Huang Xin 267fe58a8c fix: reduce screen flash with different background colors when app starts, closes #1915 (#1922) 2025-08-28 20:02:53 +02:00
Huang Xin 1b00d8c41c fix: support importing azw3 files on Android, closes #1920 (#1921) 2025-08-28 16:11:30 +02:00
Huang Xin cb126613b1 perf(sync): incremental sync of library books (#1917) 2025-08-27 19:04:57 +02:00
Huang Xin 515bfee2a1 fix(kosync): normalize xpointer to improve KOReader sync tolerance, closes #1857 (#1914) 2025-08-27 09:18:32 +02:00
Huang Xin 584f3511f8 refactor(kosync): move kosync into reader sidebar menu and add manual pull/push trigger (#1912) 2025-08-27 13:32:00 +08:00
Huang Xin 3ea54e6725 fix: display hidden footnotes, closes #1847 (#1907) 2025-08-26 12:45:12 +02:00
Huang Xin 48212d892f fonts: purge custom fonts when reseting fonts config (#1906) 2025-08-26 11:23:34 +02:00
Huang Xin 977c61b914 refactor: use useFileSelector hook for all file selection (#1905) 2025-08-26 10:04:10 +02:00
Huang Xin 66fceb2313 chore: add 10MB of grace bytes for storage quota (#1904) 2025-08-26 07:28:15 +02:00
Huang Xin 76feefff00 layout: fix overflow of some font names in custom fonts, closes #1901 (#1903) 2025-08-26 06:35:43 +02:00
Huang Xin 1be43ff704 fix: close reader window when trying to go to library in separate reader window, closes #1899 (#1900) 2025-08-25 18:01:06 +02:00
Huang Xin b6d4a547e5 chore: fix typo (#1898) 2025-08-25 09:41:36 +02:00
Huang Xin 5ee860f1e8 refactor: use safe insets from native for Android, closes #1793 and closes #1886 (#1897) 2025-08-25 09:38:49 +02:00
dependabot[bot] 0b01132d88 chore(deps): bump actions/setup-java in the github-actions group (#1896)
Bumps the github-actions group with 1 update: [actions/setup-java](https://github.com/actions/setup-java).


Updates `actions/setup-java` from 4 to 5
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 09:13:58 +02:00
Huang Xin b98c487919 theme: fix themed background color for PDFs on macOS, closes #1887 (#1894) 2025-08-24 08:29:45 +02:00
Huang Xin b43b08d423 fix: init traffic light properly in library page on macOS, closes #1872 (#1891) 2025-08-24 06:33:52 +02:00
Huang Xin 3ddb6e6422 fix: handle some cases where footnote is empty, closes #1880 (#1883) 2025-08-23 10:28:51 +02:00
Huang Xin ea9146be5b fonts: parse font family as well as font style when importing fonts, closes #1876 (#1881) 2025-08-23 10:27:58 +02:00
Huang Xin 78cb1f45e4 chore: fix workflow dependency for release (#1874) 2025-08-22 17:51:01 +02:00
Huang Xin e472d1cf1e release: version 0.9.75 (#1873) 2025-08-22 17:47:24 +02:00
shaqtiktok 75dc04d598 fix(tts): reuse audio object in the same paragraph for better performance, closes #1777 (#1853)
* Remove stopInternal which causes audio delaying

* Change audio obj to not be recreated every sentence

* refactor abort signal handler

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-08-22 17:22:34 +02:00
Huang Xin fc4c033cf3 layout: layout tweaks on the custom fonts panel (#1871) 2025-08-22 12:35:20 +02:00
Huang Xin dbee054838 feat: apply custom fonts directly in custom font panel (#1870) 2025-08-22 12:17:57 +02:00
Huang Xin 45b805dcd4 layout: keep book title align center of the blank space when there are window buttons, closes #1867 (#1869) 2025-08-22 10:42:34 +02:00
Huang Xin a8ac54b51c layout: fix position of close button miss-match between reader and library page on Windows and Linux, closes #1866 (#1868) 2025-08-22 10:05:00 +02:00
German Shein 86f705eae9 feat: support author sorting (last name first), closes #1799 (#1865)
* [Issue #1799](https://github.com/readest/readest/issues/1799): Changing the name order when sorting the book by Author by placing the last name first in Arabic, Tibetan, German, English, Spanish, French, Hindi, Italian, Dutch, Polish, Portuguese, Russian, Thai, Turkish and Ukrainian languages

* refactor author sort

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-08-22 07:59:59 +02:00
Huang Xin d390209dab feat: support importing TTF/ODF fonts, closes #979 and closes #1708 (#1864) 2025-08-21 21:49:08 +02:00
Huang Xin 149f94be4c css: ensure workarounds don’t interfere with body background color (#1859) 2025-08-20 18:30:20 +02:00
Huang Xin ef1a1eab98 layout: consistent label font weight for settings panels (#1856) 2025-08-20 12:14:45 +02:00
lijiahao66666 dc7c6e14bc fix(translator): refresh translation when provider is changed in translator popup (#1855)
– Add the translate function to the dependency array in the TranslatorPopup component
– This change ensures that the translation content is re-fetched whenever the translate function is updated

Co-authored-by: 李家豪 <7904127+li_jiahaojj@user.noreply.gitee.com>
2025-08-20 11:54:20 +02:00
Huang Xin 8c31dc85f9 chore: bump next.js, opennext, wrangler and supabase to latest versions (#1851) 2025-08-20 05:57:28 +02:00
Huang Xin 7b8d1ddc35 chore: bump tauri to latest dev branch (#1849) 2025-08-20 05:15:44 +02:00
Huang Xin 8c12399732 layout: fix footer bar layout in landscape mode on Android, closes #1803 (#1843) 2025-08-19 15:49:38 +02:00
Huang Xin 93a4b1a448 css: fix unexpected align center for some EPUBs (#1842) 2025-08-19 15:05:26 +02:00
Huang Xin 04b0752b22 layout: fix drop down in TTS panel cannot open on older iOS, closes #1810 (#1841) 2025-08-19 15:02:02 +02:00
Huang Xin 5137c08204 chore: more aggressive cache for CI (#1839) 2025-08-19 10:21:20 +02:00
Huang Xin ec0b44fb9f reader: fix collapse of nested TOC for some EPUBs, closes #1820 and closes #1813 (#1837) 2025-08-19 09:55:25 +02:00
Huang Xin 0bf83dfe67 css: use monospace font for code blocks when overriding custom book fonts, closes #1805 (#1836) 2025-08-19 07:56:10 +02:00
Huang Xin b151b70cb9 fix: don't proxy network connection from Tailscale IP addresses, closes #1834 (#1835) 2025-08-19 05:02:29 +02:00
Huang Xin f2640359a0 release: version 0.9.72 (#1831) 2025-08-18 17:43:09 +02:00
Huang Xin 079aeaedb0 fix(sync): support custom koreader sync server hosted in LAN, closes #1800 (#1830) 2025-08-18 17:35:49 +02:00
Huang Xin bfacadb964 layout: fix options list align right on Windows (#1829) 2025-08-18 16:10:06 +02:00
Huang Xin 2e98ed44ee tts: fix edge tts, closes #1821 (#1828) 2025-08-18 14:44:38 +02:00
dependabot[bot] 952d2a3553 chore(deps): bump actions/checkout in the github-actions group (#1827)
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 4 to 5
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 13:36:01 +02:00
StepanSad 225aa0ca59 Update translation.json (#1826) 2025-08-17 20:15:14 +08:00
Huang Xin 37f718b84b fix: adjust snap threshold to avoid pagination changes when toggling toolbars, closes #1807 (#1811) 2025-08-14 17:00:52 +02:00
Huang Xin db8f53a6e1 css: background color for dialogs and images, closes #1797 (#1798) 2025-08-13 15:37:52 +02:00
Huang Xin ce345ad67f fix(koplugin): add expected 301 status code (#1791) 2025-08-12 21:33:51 +02:00
Huang Xin 8e53e625a4 fix(koplugin): fix typo of saveSetting, closes #1788 (#1789) 2025-08-12 20:20:43 +02:00
Huang Xin 3350bdbdd3 release: version 0.9.71 (#1787) 2025-08-12 18:59:04 +02:00
Huang Xin 634d789654 css: fix initial text align (#1786) 2025-08-12 18:37:00 +02:00
Huang Xin 0dfa8e96f5 feat(sync): add readest koplugin for progress sync, also implements #1729 (#1785) 2025-08-12 18:24:47 +02:00
Huang Xin 3698e6ca28 sync: refactor koreader sync settings (#1783)
* sync: refactor koreader sync settings

* i18n: added Tibetan translations, closes #1780
2025-08-11 19:41:39 +02:00
Zeedif 595608bd62 feat: Implement KOReader Progress Synchronization (#1770)
* feat(sync): implement KOReader progress synchronization

This commit introduces a comprehensive feature to synchronize reading progress with a KOReader sync server. It includes a compatibility layer to handle discrepancies between Readest's CFI-based progress and KOReader's XPointer/page-based progress, primarily using the `percentage` field as a common ground.

Key additions include:
- A new settings panel under "KOReader Sync" for server configuration, authentication, and sync strategy management (e.g., prompt on conflict, always use latest).
- A conflict resolution dialog that appears when remote progress differs significantly from local progress, allowing the user to choose which version to keep.
- A client-side `useKOSync` hook to manage the entire synchronization lifecycle, including API calls, state management, and conflict resolution logic.
- A new API endpoint `/api/kosync` that acts as a secure proxy to the user-configured KOReader sync server, handling authentication and forwarding requests.
- Logic to differentiate between paginated (PDF/CBZ) and reflowable (EPUB) formats, using page numbers for paginated files where possible and falling back to percentage for reliability.
- Spanish translations for all UI elements related to the KOReader sync feature.
- Addition of `uuid` package to generate a unique `device_id` for sync purposes.

Refactor:
- The `debounce` utility has been improved to include `flush` and `cancel` methods, allowing for more precise control over debounced function execution, which is now used in the sync hook.

* fix(kosync): add support for converting between XPointer and CFI in progress synchronization

* fix(kosync): update navigation method to use select instead of goTo for paginated formats

* fix(kosync): refactor synchronization settings and improve conflict resolution handling

* fix(kosync): add event dispatcher for flushing KOReader synchronization

* fix(sync): handle xpointer in a different section, fix styling

* i18n: update translations

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-08-11 17:53:28 +02:00
Huang Xin b8bb1ee71d fix(sync): correct xpointer spine index and omit certain tag index (#1781) 2025-08-11 15:25:16 +02:00
arutonee1 4298213ce4 feat: added option to delete only the local copy of a book (#1773)
* feat: added button to delete the local copy of a book

* refactor: merged deletion api and messages

* fix: included translations for deletion messages

* updated translations

* refactor the deletion dropdown menu

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-08-11 10:38:34 +02:00
Huang Xin 5671460618 sync: add xcfi to convert between readest epubcfi and koreader xpointer (#1774) 2025-08-09 19:01:54 +02:00
Huang Xin 452dc9f3e6 chore: cache nextjs build for CI (#1771) 2025-08-09 07:28:38 +02:00
Andres Puello 09e65211b4 feat: add option to config reading progress format (#1761)
* feat: added percentage option and set by default

* feat: added decimal percentaje

* fix: fixed issue that the function of format didn't look for typeof

* fix: Added revision fixes

* fix: Added revision fixes and changes

* fix: solved about styling code

* fix: solved about styling code on book.ts and translation.json

* fix: changed lines useEffect line that is escencial to Layoutpanel.tsx, and ProgressInfo.tsx has correct render like last version (Loc.) nd its separator

* fix: correct SUPPORTED_LANGS key and disable style reapplication in saveViewSettings

* i18n for the progress style config

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2025-08-09 06:23:18 +02:00
Huang Xin f46be89036 fix: apply system color scheme for iOS in auto theme mode, closes #1762 (#1767) 2025-08-08 13:45:04 +02:00
Huang Xin f2f744a2fe css: mix with background color for horizontal rule, closes #1649 (#1759) 2025-08-07 11:18:56 +02:00
Huang Xin ceb1963b88 auth: avoid infinite loop of redirect and auth after token is expired (#1758) 2025-08-07 05:40:13 +02:00
Huang Xin 23d74b567a css: apply monospace font settings for EPUBs, closes #1754 (#1757) 2025-08-07 03:54:44 +02:00
StepanSad 5014932a8f i18n: Update translation.json (#1756) 2025-08-07 07:20:14 +08:00
Huang Xin 6a5694d2b2 feat: readest koplugin for progress sync (#1753) 2025-08-06 17:12:00 +02:00
Huang Xin df074082a8 fix: thread-safe NativeFile read for PDF on Android, closes #1748 (#1751) 2025-08-06 16:24:56 +02:00
Huang Xin 847d514441 fix: NativeFile access for file URI when importing files on iOS, closes #1746 (#1747) 2025-08-05 18:48:42 +02:00
Huang Xin b2a71da2b0 fix: chunk of cache item now has enough space for read of MAX_CACHE_CHUNK_SIZE, closes #1392 (#1744) 2025-08-04 16:35:27 +02:00
Huang Xin 3e5e4d2946 compat: detect book language from text for invalid language code in metadata (#1743) 2025-08-04 14:55:18 +02:00
Huang Xin e3c05e7648 feat: add reset password button in user page (#1742) 2025-08-04 14:12:19 +02:00
Huang Xin df9ca2d2fa api: migrate usage stats from KV to db (#1739) 2025-08-03 05:36:33 +02:00
Huang Xin 1631ece2bd docs: doc submodule update as dependencies 2025-08-03 03:39:24 +02:00
Huang Xin 2ae25f3bbe translator: add more translator languages (#1738) 2025-08-02 17:09:09 +02:00
Huang Xin 511093a6ef tts: tts now works when language codes are mistakenly set with language names (#1737) 2025-08-02 16:52:32 +02:00
Huang Xin 1ef126f820 release: version 0.9.69 (#1733) 2025-08-02 03:36:10 +02:00
Huang Xin 1788b86ced chore: bump to upstream foliate-js (#1732) 2025-08-02 03:24:58 +02:00
Huang Xin 3111e93054 layout: fix unintended reader view scroll when highlighting, closes #1716 (#1731) 2025-08-02 02:58:58 +02:00
Huang Xin 288abc678c refactor: unified path resolver on all platforms (#1730) 2025-08-01 16:51:17 +02:00
Huang Xin 7e559c5b90 metadata: fix formatting for subjects, closes #1724 (#1727) 2025-08-01 00:19:58 +08:00
Huang Xin eaaeb844f3 txt: fix language detection when parsing TXT files, closes #1720 (#1723) 2025-07-31 08:52:25 +02:00
Huang Xin 097fde203d css: overriding book color also applies to the font elements (#1721) 2025-07-31 04:40:08 +02:00
Huang Xin efd85e67d9 api: production for apple iap verifier (#1719) 2025-07-31 01:41:55 +02:00
Huang Xin bd4bf459e3 epub: fix some images are not displayed in EPUBs, closes #1709 (#1718) 2025-07-30 14:11:55 +02:00
Huang Xin 8fb1745dbb config: add an option to disable double click, closes #1713 (#1715) 2025-07-30 11:35:07 +02:00
Huang Xin 47c6d6d058 layout: fix cover image width in fit mode in list view (#1714) 2025-07-30 11:29:31 +02:00
Huang Xin 564693d456 security: add updater permission for standalone reader window, closes #1710 (#1712) 2025-07-30 05:00:46 +02:00
Huang Xin aa3cd2a0c5 txt: trim punctuations in parsed author names (#1707)
* txt: trim punctuations in parsed author names

* release: version 0.9.68
2025-07-29 20:50:21 +02:00
Huang Xin c581f8ab47 txt: more robust TXT parsing (#1706) 2025-07-29 20:06:55 +02:00
Huang Xin 63ed763499 api: handle downloading books of sanitized titles (#1705) 2025-07-29 18:23:19 +08:00
Huang Xin 213fc0d21e api: handle more string sanitization (#1702) 2025-07-28 19:12:42 +02:00
Huang Xin 9bc1494582 api: sanitize string before saving into db (#1701) 2025-07-28 18:44:26 +02:00
Huang Xin 33b2ba1609 chore: add legal links in about window and user page (#1700) 2025-07-28 18:19:45 +02:00
Huang Xin b9add62ba7 translation: skip translating pre, code and math tags, closes #1693 (#1698) 2025-07-28 09:18:19 +02:00
Huang Xin 23fa2dc8b2 css: fix hard-coded font color, closes #1695 (#1697) 2025-07-28 08:36:10 +02:00
Huang Xin 67ac09a290 premium: increased cloud sync storage for premium users (#1696) 2025-07-28 08:25:22 +02:00
Huang Xin f10c14ae96 api: batch updating daily usage key in KV (#1694) 2025-07-28 06:25:47 +02:00
Huang Xin 438d3ae0c2 config: default to open file with new window (#1691) 2025-07-27 19:12:19 +02:00
Huang Xin 842062fe44 perf: multi-part download with range access (#1690) 2025-07-27 18:56:41 +02:00
Huang Xin d01897d62a fix: load backup library data if main library data is unavailable, closes #1672 (#1689) 2025-07-27 16:48:58 +02:00
Huang Xin 6eeb8e7580 layout: fix insets for double borders and add book spine decorator (#1688) 2025-07-27 14:36:55 +02:00
Huang Xin 9cebadba57 font: fix broken links for online CJK fonts (#1687) 2025-07-27 08:25:25 +02:00
Huang Xin e5ec9abca3 chore: suppress warnings from old objc crate (#1686) 2025-07-27 08:03:45 +02:00
Huang Xin 5e7f09d5c8 perf: eliminate redundant re-renders of book cover components (#1685) 2025-07-27 07:02:05 +02:00
Huang Xin ffa193d116 fix: importing books from url and set downloaded timestamp for reimported books (#1684) 2025-07-26 14:34:51 +02:00
Huang Xin 686f8988bc api: use node api endpoint for iap verifying (#1683) 2025-07-26 13:34:36 +02:00
Huang Xin 8d5c98004b api: ensure proper string decoded on edge runtimes (#1680) 2025-07-25 21:13:01 +02:00
Huang Xin 214411919f iap: use sandbox environment for testflight (#1679) 2025-07-25 19:49:53 +02:00
Huang Xin 42c2825e90 feat: enable IAP for upgrading to Readest Premium on iOS (#1678) 2025-07-25 19:08:53 +02:00
Huang Xin 8974a87168 feat: add IAP server api (#1676) 2025-07-25 14:44:56 +02:00
Huang Xin f3e9983742 feat: add IAP in native bridge plugin for iOS (#1673) 2025-07-24 14:54:17 +02:00
初五 beaf034035 docs: fix outdated repository links and spelling error (#1669)
* docs: update outdated repository links in CONTRIBUTING.md

- Update issue tracker link from chrox/readest to readest/readest    
- Update new issue link from chrox/readest to readest/readest

* fix: correct spelling of "quota" in release notes

- Fix typo "quata" -> "quota" in 0.9.30 release notes
2025-07-23 20:00:55 +02:00
Huang Xin a5f18ab024 release: version 0.9.67 (#1664) 2025-07-22 16:11:00 +02:00
Huang Xin d1f5934947 library: various fixes on metadata editor and bookshelf (#1663)
* i18n: update translations

* library: various fixes on metadata editor and bookshelf

* chore: enable parallel web builds checking
2025-07-22 16:04:44 +02:00
Huang Xin f03d6f6861 feat: search in book format, group names and descriptions (#1662) 2025-07-22 11:40:14 +02:00
Huang Xin 20523b7eaf PDF: Support custom background theming for PDF files, closes #1649 (#1661) 2025-07-22 11:34:38 +02:00
Huang Xin f31c9b2a98 layout: fix hardcoded image layout in fixed layout documents (#1660) 2025-07-22 10:40:21 +02:00
Huang Xin 93071e727f linux: fixed multiple instances created in OAuth, closes #1654 (#1659) 2025-07-22 09:00:19 +02:00
Huang Xin 2d12210606 css: multiply img color in light mode when overriding book color (#1656)
This fixed image color issue for EPUBs in #1649.
2025-07-21 18:17:16 +02:00
Huang Xin 88ccc528d4 layout: hover header to show traffic light window control on macOS, closes #1645 (#1653) 2025-07-21 17:16:58 +02:00
Yurii Kostyukov 9d3fc07865 feat: Added Yandex Translator (#1652) 2025-07-21 17:13:13 +02:00
Huang Xin 6d465a40fb fix: don't use comma as separator when parsing filenames, closes #1622 (#1650) 2025-07-21 15:32:10 +02:00
Huang Xin 01c7e4c2e2 chore: fixed failed AppImage builds for Linux 2025-07-21 20:39:57 +08:00
Huang Xin 4005858242 release: version 0.9.66 (#1643) 2025-07-20 23:12:40 +02:00
Huang Xin c24f951375 fix: set xdg-mime with mime type other than scheme, closes #1621 (#1641) 2025-07-21 05:02:22 +08:00
Huang Xin dbe1efd1e9 tts: convert iso6392 language code to iso6391 to filter tts voices, closes #1627 (#1639) 2025-07-20 22:10:14 +02:00
Huang Xin 0299cce343 library: fix book not redownloaded for the redownload button in detail modal, closes #1628 (#1638) 2025-07-20 21:00:29 +02:00
Huang Xin ca9f504329 layout: fix layout for auth and user page (#1637) 2025-07-20 20:05:55 +02:00
Huang Xin df3527ceca fix: chaining file open with OS opening the highest precedence, closes #1622 (#1636) 2025-07-20 17:09:19 +02:00
Huang Xin 73d0838291 doc: run a preview build to identify compatibility issues between OpenNext, Next.js, and Supabase (#1635) 2025-07-20 11:32:00 +02:00
Huang Xin 8e3574509e chore: downgrade next.js to 15.3 (#1634)
Until https://github.com/opennextjs/opennextjs-cloudflare/issues/667 is fixed.
2025-07-20 11:12:06 +02:00
Huang Xin 9bdf375304 api: fix cors for api with new nextjs version (#1633) 2025-07-20 10:24:28 +02:00
Huang Xin effa922597 chore: bump tauri, next and zustand to latest versions (#1631) 2025-07-20 09:42:32 +02:00
Huang Xin fe484257a0 doc: add deepwiki badge and link (#1630) 2025-07-20 07:02:14 +02:00
Huang Xin cc0cd9a114 layout: fix nested toc items not expanded in very long toc list, closes #1625 (#1629) 2025-07-20 06:42:31 +02:00
Huang Xin 916d63806e chore: fix loading chunk error of optional chaining for Android WebView below 80 (#1626) 2025-07-19 20:24:30 +02:00
Huang Xin 59d0118067 chore: handle ChunkLoadError by refreshing page (#1619) 2025-07-19 06:37:13 +02:00
Huang Xin 957c6b9f32 fix: update book cover image from metadata in sidebar (#1615) 2025-07-18 19:11:02 +02:00
Huang Xin 9c5a1147fa release: version 0.9.65 (#1614) 2025-07-18 18:31:38 +02:00
Huang Xin 60ad6706ff ios: skip context menu when long-press on book cover, closes #1612 (#1613) 2025-07-18 18:22:59 +02:00
Huang Xin d9199d1182 sync: also sync book metadata (#1611) 2025-07-18 17:59:05 +02:00
Huang Xin 219edb9faf translation: fix translation not working for table of contents (#1610) 2025-07-18 11:54:26 +02:00
Huang Xin 30a0227ef3 layout: unset text indent inside of list elements (#1609) 2025-07-18 11:26:28 +02:00
Huang Xin 29b5a7cb88 tts: skip text to speech for rubys and footnote anchors, closes #1334 (#1608) 2025-07-18 11:10:12 +02:00
Huang Xin abb727870e tts: handle invalid language code and show no voices hints, closes #1579 (#1607) 2025-07-18 09:27:51 +02:00
Dave Vasilevsky af84a8b110 chore: match dev-web command to docs (#1606) 2025-07-18 06:50:41 +02:00
Huang Xin 0dea5d3094 layout: maintain the layout of anchor elements while increasing their tap target size, closes #1603 (#1605) 2025-07-18 06:26:54 +02:00
Huang Xin 527b95521e fix: replace fallback book cover with new cover image (#1604) 2025-07-18 06:03:22 +02:00
Huang Xin 396b23ddb4 css: named container classes for easier css customization, closes #1598 (#1600) 2025-07-17 20:17:51 +02:00
Huang Xin ee0d1549bd layout: add window borders on Linux, closes #1570 (#1599) 2025-07-18 01:40:12 +08:00
Huang Xin 6da6b85530 feat: support multiple reader windows on desktop, closes #259 (#1596) 2025-07-17 10:21:37 +02:00
StepanSad cde055dcb7 Update translation.json (#1595) 2025-07-17 05:03:39 +02:00
Huang Xin 08957ce3d7 release: version 0.9.64 (#1589) 2025-07-15 19:40:03 +02:00
Huang Xin 33515f1f09 fix: save custom cover images in apps (#1588) 2025-07-15 19:33:13 +02:00
Huang Xin e3c411f043 feat: support to edit book metadata, closes #753 (#1583) 2025-07-14 19:46:57 +02:00
StepanSad eda71725da Update translation.json (#1581) 2025-07-14 20:09:46 +08:00
StepanSad f19f45c00e Fixed bad Ukrainian translation. (#1576) 2025-07-12 18:01:41 +02:00
Huang Xin 6fb7897092 chore: flatpak with custom oauth (#1574) 2025-07-11 11:28:43 +08:00
Huang Xin 2de941d7fb doc: add appdata metainfo for Flathub (#1569) 2025-07-10 14:10:40 +02:00
Huang Xin 3e4b7ebb13 css: remove unintended indent for images, closes #1567 (#1568)
* chore: target Android SDK to version 36

* css: remove unintended indent for images, closes #1567
2025-07-10 12:05:07 +02:00
Huang Xin 2b52f82b57 fix: bookmark ribbon is now placed correctly when sidebar is pinned (#1565) 2025-07-09 18:23:55 +02:00
Huang Xin 9fb7e80757 fix: pull down to refresh is now more smoother and responsive (#1564) 2025-07-09 18:01:33 +02:00
Huang Xin 38869ce438 search: more responsive full-text search, closes #1558 (#1562) 2025-07-09 12:36:22 +02:00
Huang Xin 1dbf93c1cf css: lighten the highlight color in dark mode, closes #1489 (#1561) 2025-07-09 10:41:40 +02:00
Huang Xin aafcab8232 layout: fix dimension of inline images, closes #1555 (#1560) 2025-07-09 09:52:51 +02:00
Huang Xin bcfe1b8830 fix: invalid href handling in EPUB (#1557) 2025-07-09 04:57:21 +02:00
Huang Xin 5db1847f7e layout: add window border on Windows 10, closes #1551 (#1556) 2025-07-08 17:24:43 +02:00
Huang Xin 165ca4a6e9 chore: add fastlane action to release to Google Play (#1554) 2025-07-08 16:18:53 +02:00
Huang Xin 9556e1305f updater: show update notes for new releases (#1552) 2025-07-08 12:13:47 +02:00
933 changed files with 163927 additions and 19281 deletions
+31
View File
@@ -0,0 +1,31 @@
# Dependencies
node_modules
**/node_modules
# Rust build artifacts
target
**/target
# Git
.git
.gitignore
# Build outputs
.next
**/.next
out
**/out
# IDE
.idea
.vscode
*.swp
# OS files
.DS_Store
Thumbs.db
# Logs
*.log
npm-debug.log*
+1 -1
View File
@@ -8,6 +8,6 @@ updates:
groups:
github-actions:
patterns:
- "*" # Group all Actions updates into a single larger pull request
- '*' # Group all Actions updates into a single larger pull request
schedule:
interval: weekly
+107 -11
View File
@@ -1,5 +1,7 @@
name: PR checks
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
@@ -10,20 +12,30 @@ jobs:
runs-on: ubuntu-latest
env:
RUSTFLAGS: '-C target-cpu=skylake'
SCCACHE_GHA_ENABLED: 'true'
RUSTC_WRAPPER: sccache
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: 'true'
- name: setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install minimal stable with clippy and rustfmt
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Cache apt packages
uses: actions/cache@v5
with:
path: /var/cache/apt/archives
key: apt-rust-lint-${{ runner.os }}
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y pkg-config libfontconfig-dev libglib2.0-dev libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libsoup-3.0-dev
- name: Format
- name: Format check
working-directory: apps/readest-app/src-tauri
run: cargo fmt --check
- name: Clippy Check
@@ -33,27 +45,111 @@ jobs:
build_web_app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: 'true'
- name: setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.1
uses: pnpm/action-setup@v5
- name: setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- name: cache Next.js build
uses: actions/cache@v5
with:
path: apps/readest-app/.next/cache
key: nextjs-web-${{ github.sha }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
nextjs-web-${{ github.sha }}-
nextjs-web-
- name: install Dependencies
working-directory: apps/readest-app
run: |
pnpm install && pnpm setup-pdfjs
pnpm install && pnpm setup-vendors
- name: build the web App
- name: run format check
run: |
pnpm format:check || (pnpm format && git diff && exit 1)
- name: install playwright browsers
working-directory: apps/readest-app
run: npx playwright install --with-deps chromium
- name: run web tests
working-directory: apps/readest-app
run: pnpm test:pr:web
- name: run lint
working-directory: apps/readest-app
run: |
pnpm build-web
pnpm lint
- name: build the web app
working-directory: apps/readest-app
run: |
pnpm build-web && pnpm check:all
build_tauri_app:
runs-on: ubuntu-latest
env:
SCCACHE_GHA_ENABLED: 'true'
RUSTC_WRAPPER: sccache
steps:
- uses: actions/checkout@v6
with:
submodules: 'true'
- name: setup pnpm
uses: pnpm/action-setup@v5
- name: setup node
uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm
- name: cache Next.js build
uses: actions/cache@v5
with:
path: apps/readest-app/.next/cache
key: nextjs-tauri-${{ github.sha }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
nextjs-tauri-${{ github.sha }}-
nextjs-tauri-
- name: install Dependencies
working-directory: apps/readest-app
run: |
pnpm install && pnpm setup-vendors
- name: setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
- name: install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
with:
key: tauri-cargo
cache-all-crates: 'true'
- name: Cache apt packages
uses: actions/cache@v5
with:
path: /var/cache/apt/archives
key: apt-tauri-${{ runner.os }}
- name: install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y pkg-config libfontconfig-dev libglib2.0-dev libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libsoup-3.0-dev xvfb
- name: run tauri tests
working-directory: apps/readest-app
run: xvfb-run pnpm test:pr:tauri
+126 -58
View File
@@ -17,14 +17,14 @@ jobs:
release_version: ${{ steps.get-release-notes.outputs.release_version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
- name: get version
run: echo "PACKAGE_VERSION=$(node -p "require('./apps/readest-app/package.json').version")" >> $GITHUB_ENV
- name: get release
id: get-release
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: |
const { data } = await github.rest.repos.getLatestRelease({
@@ -35,7 +35,7 @@ jobs:
core.setOutput('release_tag', data.tag_name);
- name: get release notes
id: get-release-notes
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
@@ -48,6 +48,63 @@ jobs:
core.setOutput('release_version', version);
core.setOutput('release_note', releaseNote);
update-release:
permissions:
contents: write
runs-on: ubuntu-latest
needs: get-release
steps:
- name: update release
id: update-release
uses: actions/github-script@v8
env:
release_id: ${{ needs.get-release.outputs.release_id }}
release_tag: ${{ needs.get-release.outputs.release_tag }}
release_note: ${{ needs.get-release.outputs.release_note }}
with:
script: |
const { data } = await github.rest.repos.generateReleaseNotes({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: process.env.release_tag,
})
const notes = process.env.release_note.split(/\d+\.\s/).filter(Boolean);
const formattedNotes = notes.map(note => `* ${note.trim()}`).join("\n");
const body = `## Release Highlight\n${formattedNotes}\n\n${data.body}`;
github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.release_id,
body: body,
draft: false,
prerelease: false
})
build-koreader-plugin:
needs: get-release
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: create KOReader plugin zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
version=${{ needs.get-release.outputs.release_version }}
plugin_zip="Readest-${version}-1.koplugin.zip"
meta_file="apps/readest.koplugin/_meta.lua"
perl -i -pe "s/^}/ version = \"${version}\",\n}/" "${meta_file}"
cd apps
zip -r ../${plugin_zip} readest.koplugin
cd ..
echo "Uploading ${plugin_zip} to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} ${plugin_zip} --clobber
build-tauri:
needs: get-release
permissions:
@@ -67,11 +124,6 @@ jobs:
release: linux
arch: aarch64
rust_target: aarch64-unknown-linux-gnu
- os: ubuntu-22.04-arm
release: linux
arch: armhf
rust_target: arm-unknown-linux-gnueabihf
args: '--target arm-unknown-linux-gnueabihf --bundles deb'
- os: macos-latest
release: macos
arch: aarch64
@@ -91,42 +143,40 @@ jobs:
runs-on: ${{ matrix.config.os }}
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: initialize git submodules
run: git submodule update --init --recursive
- name: setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.14.4
uses: pnpm/action-setup@v5
- name: setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
cache: pnpm
- name: setup Java (for Android build only)
if: matrix.config.release == 'android'
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '17'
- name: setup Android SDK (for Android build only)
if: matrix.config.release == 'android'
uses: android-actions/setup-android@v3
uses: android-actions/setup-android@v4
- name: install NDK (for Android build only)
if: matrix.config.release == 'android'
run: sdkmanager "ndk;27.0.11902837"
run: sdkmanager "ndk;28.2.13676358"
- name: install dependencies
run: pnpm install
- name: copy pdfjs-dist to public directory
run: pnpm --filter @readest/readest-app setup-pdfjs
- name: copy pdfjs-dist and simplecc-dist to public directory
run: pnpm --filter @readest/readest-app setup-vendors
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
@@ -153,6 +203,7 @@ jobs:
echo 'PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig:/usr/share/pkgconfig' >> $GITHUB_ENV
echo 'PKG_CONFIG_SYSROOT_DIR=/usr/arm-linux-gnueabihf' >> $GITHUB_ENV
echo 'CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc' >> $GITHUB_ENV
echo 'CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS=--cfg=io_uring_skip_arch_check' >> $GITHUB_ENV
- name: create .env.local file for Next.js
run: |
@@ -167,7 +218,7 @@ jobs:
if: matrix.config.release == 'android'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/27.0.11902837
NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/28.2.13676358
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: |
@@ -177,11 +228,6 @@ jobs:
pnpm tauri icon ../../data/icons/readest-book.png
git checkout .
MANIFEST="src-tauri/gen/android/app/src/main/AndroidManifest.xml"
PERMISSION_LINE='<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>'
grep -q 'REQUEST_INSTALL_PACKAGES' "$MANIFEST" || \
sed -i "/android.permission.INTERNET/a \ $PERMISSION_LINE" "$MANIFEST"
pushd src-tauri/gen/android
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
@@ -234,10 +280,15 @@ jobs:
echo "Uploading updated latest.json to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} latest.json --clobber
- name: Override tauri-cli with custom AppImage format (Linux)
if: matrix.config.release == 'linux'
run: cargo install tauri-cli --git https://github.com/tauri-apps/tauri --branch feat/truly-portable-appimage --force
- uses: tauri-apps/tauri-action@v0
if: matrix.config.release != 'android'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: 'true'
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
@@ -260,12 +311,22 @@ jobs:
echo "Uploading release notes to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} apps/readest-app/release-notes.json --clobber
- name: upload portable binaries (Windows only)
- name: build and upload portable binaries (Windows only)
if: matrix.config.os == 'windows-latest'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
shell: bash
run: |
echo "Building Portable Binaries"
pushd apps/readest-app/
echo "NEXT_PUBLIC_PORTABLE_APP=true" >> .env.local
pnpm tauri build ${{ matrix.config.args }}
popd
echo "Uploading Portable Binaries"
arch=${{ matrix.config.arch }}
version=${{ needs.get-release.outputs.release_version }}
@@ -288,41 +349,48 @@ jobs:
echo "Uploading $bin_file to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} $bin_file --clobber
update-release:
permissions:
contents: write
runs-on: ubuntu-latest
needs: [get-release, build-tauri]
echo "Signing portable binary"
pushd apps/readest-app/
pnpm tauri signer sign "../../$bin_file"
popd
echo "Uploading signature to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} $bin_file.sig --clobber
steps:
- name: update release
id: update-release
uses: actions/github-script@v7
- name: download and update latest.json for Windows portable release
if: matrix.config.os == 'windows-latest'
env:
release_id: ${{ needs.get-release.outputs.release_id }}
release_tag: ${{ needs.get-release.outputs.release_tag }}
release_note: ${{ needs.get-release.outputs.release_note }}
with:
script: |
const { data } = await github.rest.repos.generateReleaseNotes({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: process.env.release_tag,
})
const notes = process.env.release_note.split(/(?:\d\.\s)/).filter(Boolean);
const formattedNotes = notes.map(note => `* ${note.trim()}`).join("\n");
const body = `## Release Highlight\n${formattedNotes}\n\n${data.body}`;
github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.release_id,
body: body,
draft: false,
prerelease: false
})
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
curl -sL https://github.com/readest/readest/releases/latest/download/latest.json -o latest.json
version=${{ needs.get-release.outputs.release_version }}
arch=${{ matrix.config.arch }}
if [ "$arch" = "x86_64" ]; then
bin_file="Readest_${version}_x64-portable.exe"
platform_key="windows-x86_64-portable"
elif [ "$arch" = "aarch64" ]; then
bin_file="Readest_${version}_arm64-portable.exe"
platform_key="windows-aarch64-portable"
else
echo "Unknown architecture: $arch"
exit 1
fi
portable_url="https://github.com/readest/readest/releases/download/${{ needs.get-release.outputs.release_tag }}/$bin_file"
portable_sig=$(cat $bin_file.sig)
jq --arg url "$portable_url" \
--arg sig "$portable_sig" \
--arg key "$platform_key" \
'.platforms[$key] = {signature: $sig, url: $url}' latest.json > tmp.$$.json && mv tmp.$$.json latest.json
echo "Uploading updated latest.json to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} latest.json --clobber
upload-to-r2:
needs: [get-release, update-release]
needs: [get-release, build-tauri]
uses: ./.github/workflows/upload-to-r2.yml
with:
tag: ${{ needs.get-release.outputs.release_tag }}
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: 'true'
- uses: amondnet/vercel-action@v25
+15
View File
@@ -1,4 +1,5 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
docker/.env
# dependencies
/node_modules
@@ -38,3 +39,17 @@ next-env.d.ts
# Rust build
target
fastlane/report.xml
fastlane/metadata/android/en-US/changelogs
*.koplugin.zip
# nix
result*
.playwright-mcp/
.claude/worktrees
.claude/settings.local.json
+15
View File
@@ -4,3 +4,18 @@
[submodule "packages/tauri"]
path = packages/tauri
url = https://github.com/readest/tauri.git
[submodule "packages/tauri-plugins"]
path = packages/tauri-plugins
url = https://github.com/readest/tauri-plugins-workspace.git
[submodule "packages/simplecc-wasm"]
path = packages/simplecc-wasm
url = https://github.com/readest/simplecc-wasm.git
[submodule "apps/readest-app/src-tauri/plugins/tauri-plugin-turso"]
path = apps/readest-app/src-tauri/plugins/tauri-plugin-turso
url = https://github.com/readest/tauri-plugin-turso.git
[submodule "apps/readest-app/.claude/skills/gstack"]
path = apps/readest-app/.claude/skills/gstack
url = https://github.com/garrytan/gstack.git
[submodule "packages/qcms"]
path = packages/qcms
url = https://github.com/mozilla/pdf.js.qcms.git
+1
View File
@@ -0,0 +1 @@
pnpm exec lint-staged
+2
View File
@@ -0,0 +1,2 @@
pnpm -C apps/readest-app lint
pnpm -C apps/readest-app test
+38 -1
View File
@@ -1 +1,38 @@
packages/foliate-js/
# Dependencies
node_modules
pnpm-lock.yaml
# Build Artifacts (Web & Rust)
.next
.open-next
.build
.tauri
out
build
dist
target
fastlane
.wrangler
# Autogenerated Tauri files
gen
**/autogenerated
**/schemas
# Submodules (External Repos)
packages
# Claude Code Skills & Config
apps/readest-app/.claude
# Vendored Assets (Generated/External Code)
apps/readest-app/public/*.js
apps/readest-app/public/vendor
apps/readest-app/src-tauri/plugins/tauri-plugin-turso
# Environment & Editor
.env
.env.*
.vscode
.idea
*.log
+1
View File
@@ -5,5 +5,6 @@
"tabWidth": 2,
"singleQuote": true,
"jsxSingleQuote": true,
"endOfLine": "lf",
"plugins": ["prettier-plugin-tailwindcss"]
}
+8
View File
@@ -0,0 +1,8 @@
{
"recommendations": [
"ms-vscode.vscode-typescript-next",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"rust-lang.rust-analyzer"
]
}
+16 -1
View File
@@ -13,4 +13,19 @@
"javascript.validate.enable": false,
"javascript.format.enable": false,
"typescript.format.enable": false,
}
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.requireConfig": true,
"prettier.documentSelectors": ["**/*.{js,jsx,ts,tsx,css,json,md,html,yml}"]
}
+4 -4
View File
@@ -3,14 +3,14 @@
When contributing to `Readest`, whether on GitHub or in other community spaces:
- Be respectful, civil, and open-minded.
- Before opening a new pull request, try searching through the [issue tracker](https://github.com/chrox/readest/issues) for known issues or fixes.
- Before opening a new pull request, try searching through the [issue tracker](https://github.com/readest/readest/issues) for known issues or fixes.
- If you want to make code changes based on your personal opinion(s), make sure you open an issue first describing the changes you want to make, and open a pull request only when your suggestions get approved by maintainers.
## How to Contribute
### Prerequisites
In order to not waste your time implementing a change that has already been declined, or is generally not needed, start by [opening an issue](https://github.com/chrox/readest/issues/new/choose) describing the problem you would like to solve.
In order to not waste your time implementing a change that has already been declined, or is generally not needed, start by [opening an issue](https://github.com/readest/readest/issues/new/choose) describing the problem you would like to solve.
For the best experience to build Readest for yourself, use a recent version of Node.js and Rust. Refer to the [Tauri documentation](https://v2.tauri.app/start/prerequisites/) for details on setting up the development environment prerequisites on different platforms.
@@ -43,8 +43,8 @@ git submodule update --init --recursive
```bash
# might need to rerun this when code is updated
pnpm install
# copy pdfjs-dist to Next.js public directory
pnpm --filter @readest/readest-app setup-pdfjs
# copy vendors dist libs to public directory
pnpm --filter @readest/readest-app setup-vendors
```
#### 3. Verify Dependencies Installation
Generated
+4281 -1356
View File
File diff suppressed because it is too large Load Diff
+25 -1
View File
@@ -2,9 +2,32 @@
members = [
"apps/readest-app/src-tauri",
"packages/tauri/crates/tauri",
"packages/tauri-plugins/plugins/fs"
]
exclude = [
"packages/qcms"
]
resolver = "2"
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
tracing = "0.1"
log = "0.4"
tauri = { version = "2", default-features = false }
tauri-build = "2"
tauri-plugin = "2"
tauri-utils = "2"
schemars = "0.8"
serde_json = "1"
thiserror = "2"
glob = "0.3"
zbus = "5.9"
dunce = "1"
url = "2"
tar = "0.4.45"
nix = "0.20.2"
glib = "0.20.0"
[workspace.package]
authors = ["Bilingify LLC"]
homepage = "https://readest.com"
@@ -15,4 +38,5 @@ edition = "2021"
rust-version = "1.77.2"
[patch.crates-io]
tauri = { path = "packages/tauri/crates/tauri" }
tauri = { path = "packages/tauri/crates/tauri" }
tauri-plugin-fs = { path = "packages/tauri-plugins/plugins/fs" }
+33 -31
View File
@@ -1,38 +1,40 @@
FROM node:22-slim
ENV PNPM_HOME="/root/.local/share/pnpm"
ENV PATH="${PATH}:${PNPM_HOME}"
RUN npm install --global pnpm
# Install necessary packages
RUN apt update -y && apt install -y --no-install-recommends \
libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
ca-certificates \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Install Rust and Cargo
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
COPY . /app
FROM docker.io/node:22-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
RUN corepack prepare pnpm@10.29.3 --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/readest-app/package.json ./apps/readest-app/
COPY patches/ ./patches/
COPY packages/ ./packages/
RUN pnpm install
RUN pnpm --filter @readest/readest-app setup-pdfjs
FROM base AS dependencies
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm --filter @readest/readest-app setup-vendors
FROM dependencies AS development-stage
COPY . .
WORKDIR /app/apps/readest-app
EXPOSE 3000
ENTRYPOINT ["pnpm", "dev-web", "-H", "0.0.0.0"]
FROM base AS build
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY
ARG NEXT_PUBLIC_APP_PLATFORM
ARG NEXT_PUBLIC_API_BASE_URL
ARG NEXT_PUBLIC_OBJECT_STORAGE_TYPE
ARG NEXT_PUBLIC_STORAGE_FIXED_QUOTA
ARG NEXT_PUBLIC_TRANSLATION_FIXED_QUOTA
COPY --from=dependencies /app/node_modules /app/node_modules
COPY --from=dependencies /app/apps/readest-app/node_modules /app/apps/readest-app/node_modules
COPY --from=dependencies /app/apps/readest-app/public/vendor /app/apps/readest-app/public/vendor
COPY --from=dependencies /app/packages/foliate-js/node_modules /app/packages/foliate-js/node_modules
COPY . .
WORKDIR /app/apps/readest-app
RUN pnpm build-web
ENTRYPOINT ["pnpm", "start-web"]
FROM build as production-stage
ENTRYPOINT ["pnpm", "start-web", "-H", "0.0.0.0"]
EXPOSE 3000
+95 -51
View File
@@ -5,20 +5,22 @@
<h1>Readest</h1>
<br>
[Readest][link-website] is an open-source ebook reader designed for immersive and deep reading experiences. Built as a modern rewrite of [Foliate](https://github.com/johnfactotum/foliate), it leverages [Next.js 15](https://github.com/vercel/next.js) and [Tauri v2](https://github.com/tauri-apps/tauri) to deliver a smooth, cross-platform experience across macOS, Windows, Linux, Android, iOS, and the Web.
[Readest][link-website] is an open-source ebook reader designed for immersive and deep reading experiences. Built as a modern rewrite of [Foliate](https://github.com/johnfactotum/foliate), it leverages [Next.js 16](https://github.com/vercel/next.js) and [Tauri v2](https://github.com/tauri-apps/tauri) to deliver a smooth, cross-platform experience across macOS, Windows, Linux, Android, iOS, and the Web.
[![Website][badge-website]][link-website]
[![Web App][badge-web-app]][link-web-readest]
[![OS][badge-platforms]][link-website]
<br>
[![][badge-hellogithub]][link-hellogithub]
[![][badge-discord]][link-discord]
[![Discord][badge-discord]][link-discord]
[![Reddit][badge-reddit]][link-reddit]
[![AGPL Licence][badge-license]](LICENSE)
[![Latest release][badge-release]][link-gh-releases]
[![Language Coverage][badge-language-coverage]][link-locales]
[![Donate][badge-donate]][link-donate]
<br>
[![Latest release][badge-release]][link-gh-releases]
[![Last commit][badge-last-commit]][link-gh-commits]
[![Commits][badge-commit-activity]][link-gh-pulse]
[![][badge-hellogithub]][link-hellogithub]
[![Ask DeepWiki][badge-deepwiki]][link-deepwiki]
</div>
@@ -43,38 +45,38 @@
<div align="left">✅ Implemented</div>
| **Feature** | **Description** | **Status** |
| --------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------- |
| **Multi-Format Support** | Support EPUB, MOBI, KF8 (AZW3), FB2, CBZ, TXT, PDF (experimental) | ✅ |
| **Scroll/Page View Modes** | Switch between scrolling or paginated reading modes. | ✅ |
| **Full-Text Search** | Search across the entire book to find relevant sections. | ✅ |
| **Annotations and Highlighting** | Add highlights, bookmarks, and notes to enhance your reading experience. | ✅ |
| **Excerpt Text for Note-Taking** | Easily excerpt text from books for detailed notes and analysis. | ✅ |
| **Dictionary/Wikipedia Lookup** | Instantly look up words and terms when reading. | ✅ |
| **[Parallel Read][link-parallel-read]** | Read two books or documents simultaneously in a split-screen view. | ✅ |
| **Customize Font and Layout** | Adjust font, layout, theme mode, and theme colors for a personalized experience. | ✅ |
| **File Association and Open With** | Quickly open files in Readest in your file browser with one-click. | ✅ |
| **Sync across Platforms** | Synchronize book files, reading progress, notes, and bookmarks across all supported platforms. | ✅ |
| **Translate with DeepL** | From a single sentence to the entire book—translate instantly with DeepL. | ✅ |
| **Text-to-Speech (TTS) Support** | Enjoy smooth, multilingual narration—even within a single book. | ✅ |
| **Library Management** | Organize, sort, and manage your entire ebook library. | ✅ |
| **Code Syntax Highlighting** | Read software manuals with rich coloring of code examples. | ✅ |
| **Feature** | **Description** | **Status** |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | ---------- |
| **Multi-Format Support** | Support EPUB, MOBI, KF8 (AZW3), FB2, CBZ, TXT, PDF | ✅ |
| **Scroll/Page View Modes** | Switch between scrolling or paginated reading modes. | ✅ |
| **Full-Text Search** | Search across the entire book to find relevant sections. | ✅ |
| **Annotations and Highlighting** | Add highlights, bookmarks, and notes to enhance your reading experience and use instant mode for quicker interactions. | ✅ |
| **Dictionary/Wikipedia Lookup** | Instantly look up words and terms when reading. | ✅ |
| **[Parallel Read][link-parallel-read]** | Read two books or documents simultaneously in a split-screen view. | ✅ |
| **Customize Font and Layout** | Adjust font, layout, theme mode, and theme colors for a personalized experience. | ✅ |
| **Code Syntax Highlighting** | Read software manuals with rich coloring of code examples. | ✅ |
| **File Association and Open With** | Quickly open files in Readest in your file browser with one-click. | ✅ |
| **Library Management** | Organize, sort, and manage your entire ebook library. | ✅ |
| **OPDS/Calibre Integration** | Integrate OPDS/Calibre to access online libraries and catalogs. | ✅ |
| **Translate with DeepL and Yandex** | From a single sentence to the entire book—translate instantly. | ✅ |
| **Text-to-Speech (TTS) Support** | Enjoy smooth, multilingual narration—even within a single book. | ✅ |
| **Sync across Platforms** | Synchronize book files, reading progress, notes, and bookmarks across all supported platforms. | ✅ |
| [**Sync with Koreader**][link-kosync-wiki] | Synchronize reading progress, notes, and bookmarks with [Koreader][link-koreader] devices. | ✅ |
| **Accessibility** | Provides full keyboard navigation and supports for screen readers such as VoiceOver, TalkBack, NVDA, and Orca. | ✅ |
| **Visual & Focus Aids** | Reading ruler, paragraph-by-paragraph reading mode, and speed reading features. | ✅ |
## Planned Features
<div align="left">🛠 Building</div>
<div align="left">🔄 Planned</div>
| **Feature** | **Description** | **Priority** |
| ------------------------------- | ------------------------------------------------------------------------------------------ | ------------ |
| **Sync with Koreader** | Synchronize reading progress, notes, and bookmarks with [Koreader][link-koreader] devices. | 🛠 |
| **AI-Powered Summarization** | Generate summaries of books or chapters using AI for quick insights. | 🛠 |
| **Keyboard Navigation** | Implement vimium-style keybindings for book navigation. | 🔄 |
| **Support OPDS/Calibre** | Integrate OPDS/Calibre to access online libraries and catalogs. | 🔄 |
| **Audiobook Support** | Extend functionality to play and manage audiobooks. | 🔄 |
| **Handwriting Annotations** | Add support for handwriting annotations using a pen on compatible devices. | 🔄 |
| **Advanced Reading Stats** | Track reading time, pages read, and more for detailed insights. | 🔄 |
| **In-Library Full-Text Search** | Search across your entire ebook library to find topics and quotes. | 🔄 |
| **Feature** | **Description** | **Priority** |
| ------------------------------- | -------------------------------------------------------------------------- | ------------ |
| **AI-Powered Summarization** | Generate summaries of books or chapters using AI for quick insights. | 🛠 |
| **Advanced Reading Stats** | Track reading time, pages read, and more for detailed insights. | 🛠 |
| **Audiobook Support** | Extend functionality to play and manage audiobooks. | 🔄 |
| **Handwriting Annotations** | Add support for handwriting annotations using a pen on compatible devices. | 🔄 |
| **In-Library Full-Text Search** | Search across your entire ebook library to find topics and quotes. | 🔄 |
Stay tuned for continuous improvements and updates! Contributions and suggestions are always welcome—let's build the ultimate reading experience together. 😊
@@ -107,9 +109,10 @@ Stay tuned for continuous improvements and updates! Contributions and suggestion
### Platform-Specific Downloads
- macOS / iOS / iPadOS : Search for "Readest" on the [App Store][link-appstore], also available on TestFlight for beta test (send your Apple ID to <readestapp@gmail.com> to request access).
- Windows / Linux / Android: Visit [https://readest.com][link-website] or the [Releases on GitHub][link-gh-releases].
- Web: Visit [https://web.readest.com][link-web-readest].
- macOS / iOS / iPadOS : Search and install **Readest** on the [App Store][link-appstore], _also_ available on TestFlight for beta test (send your Apple ID to <readestapp@gmail.com> to request access).
- Windows / Linux / Android: Visit and download **Readest** at [https://readest.com][link-website] or the [Releases on GitHub][link-gh-releases].
- Linux users can also install [Readest on Flathub][link-flathub].
- Web: Visit and use **Readest for Web** at [https://web.readest.com][link-web-readest].
## Requirements
@@ -119,8 +122,8 @@ Stay tuned for continuous improvements and updates! Contributions and suggestion
For the best experience to build Readest for yourself, use a recent version of Node.js and Rust. Refer to the [Tauri documentation](https://v2.tauri.app/start/prerequisites/) for details on setting up the development environment prerequisites on different platforms.
```bash
nvm install v22
nvm use v22
nvm install v24
nvm use v24
npm install -g pnpm
rustup update
```
@@ -134,16 +137,16 @@ To get started with Readest, follow these steps to clone and build the project.
```bash
git clone https://github.com/readest/readest.git
cd readest
git submodule update --init --recursive
```
### 2. Install Dependencies
```bash
# might need to rerun this when code is updated
git submodule update --init --recursive
pnpm install
# copy pdfjs-dist to Next.js public directory
pnpm --filter @readest/readest-app setup-pdfjs
# copy vendors dist libs to public directory
pnpm --filter @readest/readest-app setup-vendors
```
### 3. Verify Dependencies Installation
@@ -165,13 +168,17 @@ For Windows targets, “Build Tools for Visual Studio 2022” (or a higher editi
pnpm tauri dev
# or start development for the Web app
pnpm dev-web
# preview with OpenNext build for the Web app
pnpm preview
```
For Android:
```bash
# Initialize the Android environment (run once)
rm apps/readest-app/src-tauri/gen/android
pnpm tauri android init
git checkout apps/readest-app/src-tauri/gen/android
pnpm tauri android dev
# or if you want to dev on a real device
@@ -197,6 +204,9 @@ pnpm tauri android build
pnpm tauri ios build
```
Please refer to our release script if you experience any issues:
https://github.com/readest/readest/blob/main/.github/workflows/release.yml
### 6. Setup dev environment with Nix
If you have Nix installed, you can leverage flake to enter a development shell
@@ -245,6 +255,32 @@ Please check the [wiki][link-gh-wiki] of this project for more information on de
- See Issue [readest/readest#358](https://github.com/readest/readest/issues/358) for further details, or head over to our [Discord][link-discord] server and open a support discussion with detailed logs of your environment and the steps youve taken.
### 2. AppImage Launches but Only Shows a Taskbar Icon
On some Arch Linux systems—especially those using Wayland—the Readest AppImage may briefly show an icon in the taskbar and then exit without opening a window.
You might see logs such as:
```
Could not create default EGL display: EGL_BAD_PARAMETER. Aborting...
```
This behavior is usually caused by compatibility issues between the bundled AppImage libraries and the systems EGL / Wayland environment.
**Workaround 1: Launch with LD_PRELOAD (recommended)**
You can preload the system Wayland client library before launching the AppImage:
```
LD_PRELOAD=/usr/lib/libwayland-client.so /path/to/Readest.AppImage
```
This workaround has been confirmed to resolve the issue on affected systems.
**Workaround 2: Use the Flatpak Version**
If you prefer a more reliable out-of-the-box experience on Arch Linux, consider using the [Flatpak build on Flathub][link-flathub] instead. The Flatpak runtime helps avoid system library mismatches and tends to behave more consistently across different Wayland and X11 setups.
## Contributors
Readest is open-source, and contributions are welcome! Feel free to open issues, suggest features, or submit pull requests. Please **review our [contributing guidelines](CONTRIBUTING.md) before you start**. We also welcome you to join our [Discord][link-discord] community for either support or contributing guidance.
@@ -257,17 +293,15 @@ Readest is open-source, and contributions are welcome! Feel free to open issues,
## Support
If Readest has been useful to you, consider supporting its development. Your contribution helps us squash bugs faster, improve performance, and keep building great features.
If Readest has been useful to you, consider supporting its development. You can [become a sponsor on GitHub](https://github.com/sponsors/readest), [donate via Stripe](https://donate.stripe.com/4gMcN5aZdcE52kW3TFgjC01), or [donate with crypto](https://donate.readest.com). Your contribution helps us squash bugs faster, improve performance, and keep building great features.
### How to Donate
### Sponsors
1. **GitHub Sponsors**
Back the project directly on GitHub:
👉 [https://github.com/sponsors/readest](https://github.com/sponsors/readest)
2. **Crypto Donations**
Prefer crypto? You can donate here:
👉 [https://donate.readest.com/](https://donate.readest.com/)
<p align="center">
<a title="Browser testing via TestMu AI" href="https://www.testmuai.com/?utm_medium=sponsor&utm_source=readest" target="_blank">
<img src="https://raw.githubusercontent.com/readest/readest/refs/heads/main/data/sponsors/testmu-ai-logo.png" style="vertical-align: middle;" width="250" />
</a>
</p>
## License
@@ -288,7 +322,9 @@ The following libraries and frameworks are used in this software:
The following fonts are utilized in this software, either bundled within the application or provided through web fonts:
[Bitter](https://fonts.google.com/?query=Bitter), [Fira Code](https://fonts.google.com/?query=Fira+Code), [Literata](https://fonts.google.com/?query=Literata), [Merriweather](https://fonts.google.com/?query=Merriweather), [Noto Sans](https://fonts.google.com/?query=Noto+Sans), [Roboto](https://fonts.google.com/?query=Roboto), [LXGW WenKai](https://github.com/lxgw/LxgwWenKai), [MiSans](https://hyperos.mi.com/font/en/), [Source Han](https://github.com/adobe-fonts/source-han-sans/), [WenQuanYi Micro Hei](http://wenq.org/wqy2/)
[Bitter](https://fonts.google.com/specimen/Bitter), [Fira Code](https://fonts.google.com/specimen/Fira+Code), [Inter](https://fonts.google.com/specimen/Inter), [Literata](https://fonts.google.com/specimen/Literata), [Merriweather](https://fonts.google.com/specimen/Merriweather), [Noto Sans](https://fonts.google.com/specimen/Noto+Sans), [Roboto](https://fonts.google.com/specimen/Roboto), [LXGW WenKai](https://github.com/lxgw/LxgwWenKai), [MiSans](https://hyperos.mi.com/font/en/), [Source Han](https://github.com/adobe-fonts/source-han-sans/), [WenQuanYi Micro Hei](http://wenq.org/wqy2/)
We would also like to thank the [Web Chinese Fonts Plan](https://chinese-font.netlify.app) for offering open-source tools that enable the use of Chinese fonts on the web.
---
@@ -299,14 +335,18 @@ The following fonts are utilized in this software, either bundled within the app
[badge-license]: https://img.shields.io/github/license/readest/readest?color=teal
[badge-release]: https://img.shields.io/github/release/readest/readest?color=green
[badge-platforms]: https://img.shields.io/badge/platforms-macOS%2C%20Windows%2C%20Linux%2C%20Android%2C%20iOS%2C%20Web%2C%20PWA-green
[badge-last-commit]: https://img.shields.io/github/last-commit/readest/readest?color=green
[badge-commit-activity]: https://img.shields.io/github/commit-activity/m/readest/readest
[badge-last-commit]: https://img.shields.io/github/last-commit/readest/readest?color=blue
[badge-commit-activity]: https://img.shields.io/github/commit-activity/m/readest/readest?color=blue
[badge-discord]: https://img.shields.io/discord/1314226120886976544?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square
[badge-hellogithub]: https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=8a5b6ade2aee461a8bd94e59200682a7&claim_uid=eRLUbPOy2qZtDgw&theme=small
[badge-donate]: https://donate.readest.com/badge.svg
[badge-deepwiki]: https://deepwiki.com/badge.svg
[badge-reddit]: https://img.shields.io/reddit/subreddit-subscribers/readest?style=flat&logo=reddit&color=F37E41
[badge-language-coverage]: https://img.shields.io/badge/coverage-53%25%20population%20🌍-green
[link-donate]: https://donate.readest.com/?tickers=btc%2Ceth%2Csol%2Cusdc
[link-appstore]: https://apps.apple.com/app/apple-store/id6738622779?pt=127463130&ct=github&mt=8
[link-website]: https://readest.com?utm_source=github&utm_medium=referral&utm_campaign=readme
[link-flathub]: https://flathub.org/en/apps/com.bilingify.readest
[link-web-readest]: https://web.readest.com
[link-gh-releases]: https://github.com/readest/readest/releases
[link-gh-commits]: https://github.com/readest/readest/commits/main
@@ -316,3 +356,7 @@ The following fonts are utilized in this software, either bundled within the app
[link-parallel-read]: https://readest.com/#parallel-read
[link-koreader]: https://github.com/koreader/koreader
[link-hellogithub]: https://hellogithub.com/repository/8a5b6ade2aee461a8bd94e59200682a7
[link-deepwiki]: https://deepwiki.com/readest/readest
[link-locales]: https://github.com/readest/readest/tree/main/apps/readest-app/public/locales
[link-kosync-wiki]: https://github.com/readest/readest/wiki/Sync-with-Koreader-devices
[link-reddit]: https://reddit.com/r/readest/
+37
View File
@@ -0,0 +1,37 @@
# Security Policy
## Supported Versions
Readest does not currently maintain separate release channels. Security updates are provided only for the latest release series.
| Version | Supported |
| ------- | ------------------ |
| 0.10.x | :white_check_mark: |
| < 0.10 | :x: |
## Reporting a Vulnerability
Please report suspected vulnerabilities privately. Do not open a public GitHub
issue or discussion for security-sensitive reports.
Use GitHub's private vulnerability reporting for this repository:
<https://github.com/readest/readest/security/advisories/new>
When submitting a report, include:
- A clear description of the issue and the affected component
- Steps to reproduce, proof of concept, or a minimal test case
- The versions, platforms, or environments you tested
- Any suggested remediation or mitigating details, if available
What to expect after you report:
- We will aim to acknowledge receipt within 3 business days.
- We may contact you for additional details, reproduction steps, or validation.
- If the report is accepted, we will work on a fix and coordinate disclosure.
- If the report is declined, we will explain why, for example if the behavior is
expected, unsupported, or not reproducible.
Please keep vulnerability details private until a fix is available and the
maintainers have approved disclosure.
+34
View File
@@ -0,0 +1,34 @@
# Readest Project Memory
## Key Reference Documents
- [Bug Fixing Patterns](bug-patterns.md) - Common bug categories, root causes, and fix strategies
- [CSS & Style Fixes](css-style-fixes.md) - EPUB CSS override patterns and the style.ts pipeline
- [TTS Fixes](tts-fixes.md) - Text-to-Speech architecture and bug patterns
- [Layout & UI Fixes](layout-ui-fixes.md) - Safe insets, z-index, platform-specific UI issues
- [Platform Compat Fixes](platform-compat-fixes.md) - Android, iOS, Linux, macOS platform-specific bugs
- [Annotator & Reader Fixes](annotator-reader-fixes.md) - Highlight, selection, accessibility bugs
## Critical Files (Most Bug-Prone)
- `src/utils/style.ts` - Central EPUB CSS transformation hub (14+ bug fixes)
- `packages/foliate-js/paginator.js` - Page layout, image sizing, backgrounds
- `src/services/tts/TTSController.ts` - TTS state machine, section tracking
- `src/hooks/useSafeAreaInsets.ts` - Safe area inset management
- `src/app/reader/components/FoliateViewer.tsx` - Reader view orchestration
- `src/app/reader/components/annotator/Annotator.tsx` - Annotation lifecycle
## Feature Notes
- [D-pad Navigation](dpad-navigation.md) — Android TV remote / keyboard arrow navigation design, key files, and pitfalls
## Architecture Notes
- foliate-js is a git submodule at `packages/foliate-js/`
- Multiview paginator: loads adjacent sections in background, multiple View/Overlayer instances per book
- Style overrides: `getLayoutStyles()` (always), `getColorStyles()` (when overriding color)
- `transformStylesheet()` does regex-based EPUB CSS rewriting at load time
- TTS uses independent section tracking (`#ttsSectionIndex`) decoupled from view
- Safe area insets flow: Native plugin -> useSafeAreaInsets hook -> component styles
- Dropdown menus use `DropdownContext` (not blur-based) for screen reader compat
## Workflow
- [Always rebase before PR](feedback_pr_rebase.md) — rebase onto origin/main before creating PRs
- [New branch per PR](feedback_pr_new_branch.md) — always create a fresh branch from main for each new PR/issue
- [Upgrade gstack locally](feedback_gstack_upgrade.md) — always upgrade from the project's .claude/skills/gstack, not global
@@ -0,0 +1,90 @@
# Annotator & Reader Fixes Reference
## Annotation System Architecture
### Key Components
- `Annotator.tsx` - Annotation lifecycle, popup display, style/color management
- `AnnotationRangeEditor.tsx` - Drag handles for adjusting selection range
- `MagnifierLoupe.tsx` - Magnifying glass during handle drag (mobile only)
- `useTextSelector.ts` - Text selection detection and processing
- `useAnnotationEditor.ts` - Editing existing annotations
- `useInstantAnnotation.ts` - Creating new annotations on selection
### Highlight Rendering
- Highlights rendered by foliate-js `Overlayer` (SVG overlayer in paginator shadow DOM, not iframe)
- Each view in multiview paginator has its own `Overlayer` instance with unique clipPath ID
- `Overlayer.add()` stores range + draw function; `redraw()` recalculates positions from stored ranges
- Colors stored as color names mapped to custom hex via `globalReadSettings.customHighlightColors`
- Sidebar uses `color-mix()` CSS function with custom colors, not Tailwind utility classes (#3273)
- Rounded highlight style supported via `vertical` option passed to overlayer (#3208)
### Multiview Overlayer Pitfalls
- **Duplicate SVG IDs**: Each overlayer creates `<clipPath>` for loupe hole — IDs MUST be unique per instance or `url(#id)` resolves to wrong element, clipping everything
- **docLoadHandler scope**: `FoliateViewer.tsx` re-adds annotations on `load` event — MUST filter by `detail.index` (loaded section), not re-add ALL annotations (overwrites drag edits)
- **MagnifierLoupe lifecycle**: Don't destroy/recreate loupe on every drag tick — `hideLoupe()` should only run on unmount, `showLoupe()` fast path updates position only
- **Stale closures in useTextSelector**: `getProgress()` must be called inside callbacks, not captured at hook top-level (useFoliateEvents deps are `[view]` only)
## Fix History
| Issue | Problem | Root Cause | Fix |
|-------|---------|------------|-----|
| #3286 | Selection stuck on first annotation | `initializedRef` guard blocked re-computation | Remove guard, consolidate style/color effects |
| #3273 | Custom colors not in sidebar | Hardcoded Tailwind classes | Use inline `style` with `color-mix()` |
| #3234 | Letter-by-letter selection on mobile | No word boundary snapping | Add `snapRangeToWords()` using `Intl.Segmenter` |
| #3208 | Hard rectangular highlights | No border radius support | Pass `vertical` option, update foliate-js |
| #3002 | Can't see text under finger | No magnification UI | New `MagnifierLoupe` component using `view.renderer.showLoupe()` |
| #3082 | No page numbers on annotations | `pageNumber` field missing | Add `pageNumber` to BookNote type, compute on create |
| #3225 | Android tools unresponsive | Premature `makeSelection()` call | Remove premature re-selection in Android path |
## Common Annotation Bugs
### Selection Issues
- **Word snapping**: Uses `Intl.Segmenter` with `granularity: 'word'` to snap selection to word boundaries
- **Android re-selection**: Don't call `makeSelection(sel, index, true)` immediately on pointer-up; let the popup flow complete
- **Range editor handles**: Remove `initializedRef` guards that prevent re-computation when switching annotations
### Color/Style Issues
- **Custom colors in sidebar**: Use inline `style={{ backgroundColor: 'color-mix(...)' }}` not Tailwind classes
- **Style synchronization**: Consolidate `selectedStyle` and `selectedColor` into one `useEffect`
- **Switching annotations**: Must call `setShowAnnotPopup(false)` and `setEditingAnnotation(null)` before setting up new annotation
## Reader/Content Fixes
### Progress Display
- Use physical `view.renderer.page` and `view.renderer.pages` for page counts (#3213, #3200)
- Last page shows 100% by fixing boundary condition (#3383)
- FB2 subsections need special handling for progress (#3136)
### Translation View (#3078)
- Problem: Page jumps back during full-text translation
- Root cause: DOM mutations from sequential translation insertions cause paginator relayout
- Fix: Batch DOM updates with 50ms timer, use bounded concurrent queue (max 5), show loading overlay
### TOC Navigation (#3124)
- Problem: Expanding TOC chapter scrolls back to current chapter
- Fix: Only scroll-into-view on navigation, not on expand/collapse
## Accessibility (a11y) Fixes
### Screen Reader (TalkBack) Support
- **Page indicator updates** (#2276): Add focus handlers on `<p>` elements that call `view.goTo(cfi)` to update position
- **Navigation buttons** (#3036): Always show prev/next buttons when screen reader active; `PageNavigationButtons.tsx`
- **Dropdown menus** (#3035): Use `DropdownContext` with overlay dismiss instead of blur-based closing
### Dropdown Architecture for a11y
- `DropdownContext` (`src/context/DropdownContext.tsx`) manages which dropdown is open globally
- Uses `useId()` for unique identification
- One dropdown open at a time
- `<Overlay>` for dismissal (tap/click outside) instead of `onBlur`
- `<details>` element with `open={isOpen}` for semantic structure
- No auto-focus-first-item (conflicts with TalkBack)
## E-ink Readability
- Use `not-eink:` Tailwind variant for colors and opacity (#3258)
- Don't use `text-primary` (blue) or low opacity on e-ink
- Highlights use foreground color in dark mode e-ink (#3299)
## Key Utility Functions
- `snapRangeToWords()` in `src/utils/sel.ts` - Word boundary snapping
- `handleAccessibilityEvents()` in `src/utils/a11y.ts` - Screen reader focus handling
- `color-mix()` CSS function for custom highlight colors with opacity
@@ -0,0 +1,119 @@
# Bug Fixing Patterns & Strategies
## Common Root Cause Categories
### 1. Overly Broad CSS Selectors
**Pattern:** A CSS rule targets too many elements, causing unintended visual side effects.
**Examples:**
- `hr { mix-blend-mode: multiply }` applied to ALL hr elements instead of only decorative ones (#3086)
- `p img { mix-blend-mode }` applied to block images, not just inline (#3112)
- `svg, img { height: auto; width: auto }` overrode explicit HTML width/height attributes (#3274)
- Background-color override applied unconditionally instead of only when user enabled color override (#3316)
**Fix Strategy:** Narrow selectors with class qualifiers (`.background-img`, `.has-text-siblings`) or attribute pseudo-selectors (`:where(:not([width]))`). Check if the rule should be conditional on a user setting.
### 2. Conditional vs Unconditional Style Overrides
**Pattern:** CSS rules meant for "Override Book Color/Layout" mode are placed in the always-active stylesheet.
**Examples:**
- Calibre `.calibre { color: unset }` was in `getLayoutStyles()` instead of `getColorStyles()` (#3448)
- Image background-color override applied without checking `overrideColor` flag (#3316, #3377)
**Fix Strategy:** Move rules to the correct conditional block: `getColorStyles()` for color overrides, `getLayoutStyles()` for layout overrides. Check the `overrideColor`/`overrideLayout` flags.
### 3. Missing EPUB Stylesheet Transformations
**Pattern:** EPUB stylesheets contain CSS that conflicts with app functionality.
**Examples:**
- `user-select: none` prevents text selection (#3370) -> regex replace in `transformStylesheet()`
- `font-family: serif/sans-serif` on body bypasses user font (#3334) -> detect and unset
- Hardcoded Calibre backgrounds persist in dark mode (#3448) -> unset in color override
**Fix Strategy:** Add regex-based transformation passes in `transformStylesheet()` in `style.ts`.
### 4. Stale State / Refs Not Reset
**Pattern:** A `useRef` or state variable is set once and never properly reset, blocking re-entry.
**Examples:**
- TTS `ttsOnRef` prevented restarting TTS from a new location (#3292)
- `initializedRef` in AnnotationRangeEditor prevented handle position updates (#3286)
- `view.tts` not nulled on shutdown prevented clean TTS restart (#3400)
- TTS safety timeout fired after pause, advancing to next sentence (#3244)
**Fix Strategy:** Check all refs/guards in the affected flow. Ensure cleanup in shutdown/unmount. Remove overly aggressive guards that prevent re-entry.
### 5. Platform API Differences
**Pattern:** A Web API behaves differently or is unavailable on certain platforms.
**Examples:**
- `navigator.getGamepads()` returns null on older Android WebView (#3245)
- `CompressionStream` unavailable on some Android versions (#3255)
- `btoa()` throws on non-ASCII characters (#3436)
- View Transitions API unsupported in WebKitGTK/Linux (#3417)
- `document.startViewTransition()` crashes on Linux
**Fix Strategy:** Always check API availability before use. Add fallback paths. Use feature detection, not platform detection when possible.
### 6. Safe Area Inset Issues
**Pattern:** UI elements overlap system bars (status bar, navigation bar, notch) on mobile.
**Examples:**
- Zoom controls behind status bar (#3426)
- Android navigation bar overlap (#3466)
- iPad sidebar insets incorrect (#3395)
- Reader page layout jump after system UI change (#3469)
**Fix Strategy:** Use `gridInsets` and `statusBarHeight` from `useSafeAreaInsets`. Use `env(safe-area-inset-*)` CSS functions. Call `onUpdateInsets()` after system UI visibility changes. See `docs/safe-area-insets.md`.
### 7. Z-Index Layering Issues
**Pattern:** Interactive elements rendered behind other layers, becoming unclickable.
**Examples:**
- Navigation buttons invisible on mobile (#3201) -> added `z-10`
- Annotation nav bar too prominent (#3386) -> reduced from `z-30` to `z-10`
- Page nav buttons behind TTS control (#3184)
**Fix Strategy:** Check z-index ordering. Use minimum necessary z-index. Reference the z-index hierarchy in the codebase.
### 8. Event Handling Race Conditions
**Pattern:** Timing issues between pointer events, native menus, and React state updates.
**Examples:**
- macOS context menu steals pointer event loop (#3324) -> 100ms setTimeout delay
- Traffic light buttons flicker due to timeout race (#3488, #3129)
- Android tool buttons unresponsive due to premature re-selection (#3225)
**Fix Strategy:** Add small delays before native menu calls. Check event state machine consistency. Remove premature re-triggers on Android.
### 9. foliate-js Rendering Issues
**Pattern:** Bugs in the lower-level EPUB renderer (paginator.js, epub.js).
**Examples:**
- Image size not constrained in double-page mode (#3432)
- Background not shown in scrolled mode (#3344)
- Section content cached incorrectly after mode switch (#3242, #3206)
- Swipe sensitivity too low for non-animated paging (#3310)
**Fix Strategy:** Check both `columnize()` and `scrolled()` code paths in paginator.js. Verify CSS variables (`--available-width`, `--available-height`) are computed correctly. Test in both paginated and scrolled modes.
### 10. Progress/Navigation Calculation Errors
**Pattern:** Page counts, progress percentages, or position tracking are wrong.
**Examples:**
- Progress shows 99.9% at last page (#3383) -> boundary condition
- Pages left shows estimated instead of physical count (#3213, #3200)
- FB2 subsection progress wrong (#3136) -> nested structure not handled
- TOC auto-scrolls on expand (#3124) -> scroll-into-view triggered too broadly
**Fix Strategy:** Use physical `view.renderer.page`/`view.renderer.pages` instead of estimated section metadata. Check boundary conditions (0-indexed vs 1-indexed, inclusive vs exclusive).
### 11. Multiview Paginator Side Effects
**Pattern:** The multiview paginator (e925e9d+) loads adjacent sections in background. Events from these loads can interfere with user interactions on the primary section.
**Examples:**
- `load` event from adjacent section triggers `docLoadHandler` which re-adds ALL annotations, overwriting drag edits
- Multiple overlayers with duplicate SVG `<clipPath>` IDs cause `url(#id)` to resolve to wrong element
- `MagnifierLoupe` destroying/recreating body clone on every drag tick triggers ResizeObserver → expand → redraw
**Fix Strategy:** Scope event handlers to the loaded section's index. Use unique IDs for SVG elements across overlayer instances. Minimize iframe DOM mutations during drag operations.
## Debugging Workflow
1. **Identify the category** from the issue description
2. **Check `style.ts`** first for any CSS-related visual bugs
3. **Check foliate-js** for rendering/layout bugs
4. **Check platform-specific code** for mobile/desktop differences
5. **Write a failing test** before implementing the fix
6. **Test in both paginated and scrolled modes** for layout changes
7. **Test on multiple platforms** for any UI change
8. **Run `pnpm build-check`** before submitting
@@ -0,0 +1,74 @@
# CSS & Style Fixes Reference
## The `style.ts` Pipeline (`src/utils/style.ts`)
This is the most bug-prone file in the codebase (14+ fixes). It handles all EPUB CSS transformations.
### Key Functions
#### `getLayoutStyles()`
- Always-active styles applied to every EPUB section
- Controls: line-height, hyphens, image sizing, table display
- Rules here should NOT be conditional on user settings
- Common mistake: putting color-related rules here instead of `getColorStyles()`
#### `getColorStyles()`
- Conditionally applied when user enables "Override Book Color"
- Controls: foreground/background colors, mix-blend modes, image backgrounds
- Gate rules on `overrideColor` flag
#### `transformStylesheet()`
- Regex-based rewriting of EPUB CSS at load time
- Runs on every stylesheet loaded from the EPUB
- Used to neutralize problematic EPUB CSS declarations
#### `applyTableStyle()`
- Post-render function that scales tables to fit available width
- Uses `getComputedStyle()` (not inline `style.width`) to read actual width
- Has two scaling paths: column-width-based and parent-container-based
### Fix History by Issue
| Issue | Problem | Fix in style.ts |
|-------|---------|-----------------|
| #3494 | Line spacing not on `<li>` | Added `li` CSS rule for `line-height` and `hyphens` |
| #3448 | Calibre colors persist | Moved `.calibre` unset to `getColorStyles()`, added `background-color: unset` |
| #3441 | Body padding/margin | Added `padding: unset; margin: unset` to body in `getLayoutStyles()` |
| #3316 | Image bg unconditional | Made `background-color` rule conditional on `overrideColor` |
| #3377 | Image bg override | Same pattern as #3316, only override when `overrideColor` is true |
| #3334 | Generic font-family | `transformStylesheet()` replaces `font-family: serif/sans-serif` with `unset` on body |
| #3370 | user-select: none | `transformStylesheet()` replaces all `user-select: none` with `unset` |
| #3284 | Table scaling | Added fallback when `totalTableWidth` is 0 but parent has width |
| #3351 | Table display broken | Added `display: table !important` to table rule |
| #3274 | Image dimensions | Changed selectors to `:where(:not([width]))` and `:where(:not([height]))` |
| #3205 | Table width reading | Changed from `style.width` to `getComputedStyle().width`, fixed CSS var unit |
| #3112 | Mix-blend on all images | Narrowed selector to `.has-text-siblings` class |
| #3086 | Mix-blend on hr | Narrowed selector to `hr.background-img` |
| #3012 | Vertical alignment | Fixed available dimensions (subtract insets), replaced `100vw/vh` with CSS vars |
### Common Patterns
1. **Adding new element rules:** Copy the pattern from `p` rules (e.g., adding `li` for #3494)
2. **EPUB CSS neutralization:** Add regex in `transformStylesheet()` to replace problematic declarations
3. **Conditional overrides:** Use `overrideColor`/`overrideLayout` flags to gate rules
4. **Selector narrowing:** Use class qualifiers or attribute pseudo-selectors to avoid over-matching
5. **Table fixes:** Always use `getComputedStyle()`, not inline style. Check both width paths.
### CSS Variables from foliate-js
- `--available-width` - Usable content width (set by paginator.js)
- `--available-height` - Usable content height
- `--full-width` - Full viewport width (numeric, multiply by 1px)
- `--full-height` - Full viewport height (numeric, multiply by 1px)
- `--overlayer-highlight-opacity` - Highlight transparency (default 0.3)
### foliate-js Rendering (`packages/foliate-js/paginator.js`)
Key functions:
- `columnize()` - Paginated layout path
- `scrolled()` - Scrolled layout path
- `setImageSize()` - Constrains image dimensions to available space
- `#replaceBackground()` - Transfers EPUB backgrounds to paginator layer
- `snap()` - Swipe gesture detection for page turning
Common issue: A fix applied to `columnize()` but not `scrolled()` (or vice versa). Always check both paths.
@@ -0,0 +1,40 @@
---
name: D-pad Navigation Design
description: Android TV / Bluetooth remote D-pad navigation architecture, key files, and pitfalls encountered during implementation
type: project
---
## D-pad Navigation Architecture
D-pad support enables Bluetooth remote controller navigation on Android TV (and keyboard arrow navigation on desktop).
### Key Files
- `src/app/reader/hooks/useSpatialNavigation.ts` — Reader toolbar D-pad navigation. Left/Right navigates between buttons, Up/Down moves between header↔footer. Auto-focuses first button on show. Uses focus-probe technique for visibility detection.
- `src/app/library/hooks/useSpatialNavigation.ts` — Library grid D-pad navigation. Arrow keys move between BookshelfItem elements. ArrowDown from outside bookshelf (e.g. header) enters the grid via window-level listener.
- `src/helpers/shortcuts.ts``onToggleToolbar` (Enter key) toggles reader toolbar visibility.
- `src/app/reader/hooks/useBookShortcuts.ts``toggleToolbar` handler shows/hides header+footer bars. Skips when a `<button>` is focused (lets native click fire).
- `src/__tests__/hooks/useSpatialNavigation.test.tsx` — Unit tests for reader toolbar navigation.
### Design Decisions
- **No third-party library**: Tried `@noriginmedia/norigin-spatial-navigation` but it failed due to init timing issues (React child effects run before parent effects) and conflicts with the existing `useShortcuts` system. Custom solution is simpler and more reliable.
- **Two `useSpatialNavigation` hooks**: Same name in different directories — library version handles grid navigation, reader version handles toolbar button navigation. Different navigation patterns but same concept.
- **Platform-agnostic hooks**: Both `useSpatialNavigation` hooks work on all platforms, not just Android.
- **Focus-probe for visibility**: `offsetParent` is unreliable for detecting visible buttons (returns null inside `position: fixed` containers on mobile). Instead, try `btn.focus()` and check if `document.activeElement === btn` — this correctly handles all hiding methods (display:none, visibility:hidden, fixed positioning).
### Pitfalls
1. **WebView spatial navigation conflict**: Android WebView has built-in spatial navigation that intercepts D-pad arrow keys and moves DOM focus between `tabIndex>=0` elements. Added `tabIndex={-1}` to non-interactive overlay elements (HeaderBar trigger, ProgressBar, FooterBar trigger, SectionInfo) to prevent focus theft.
2. **`eventDispatcher.dispatchSync` short-circuits**: When multiple handlers are registered for `native-key-down`, the first handler returning `true` stops propagation. The FooterBar's Back handler fires before the Reader's. Both must independently call `blur()` — can't rely on the Reader's handler running.
3. **Must blur on toolbar dismiss**: When Back/Escape dismisses the toolbar, the focused button must be blurred. Otherwise `document.activeElement` remains a hidden button, and `toggleToolbar` skips Enter when `activeElement.tagName === 'BUTTON'`. Blur is called in FooterBar's handleKeyDown (for Back and Escape) and in Reader's handleKeyDown.
4. **Arrow key trapping must use `stopPropagation`**: Without it, arrow keys bubble to `window` where `useShortcuts` handles them as page turns. The toolbar keydown handler on the container div calls `e.stopPropagation()` + `e.preventDefault()` to prevent this.
5. **Library grid needs window-level listener**: The bookshelf container keydown handler only fires when focus is inside it. A separate `window` keydown listener handles ArrowDown from the header into the grid (when focus is outside the container).
6. **Auto-focus race on toolbar show**: Both header and footer bars auto-focus their first button when `isVisible` becomes true simultaneously. The last effect to run wins. This is acceptable — user can navigate between them with Up/Down.
7. **`offsetParent` null in fixed containers**: On mobile, `.footer-bar` uses `position: fixed`. All child buttons have `offsetParent === null`, making `offsetParent`-based visibility checks useless. The focus-probe approach (try focus, check activeElement) is the reliable alternative.
@@ -0,0 +1,11 @@
---
name: gstack upgrade location
description: Always upgrade gstack from the project directory (.claude/skills/gstack), not from a global install
type: feedback
---
When upgrading gstack, always run the upgrade from the current project's `.claude/skills/gstack` directory (local-git install), not from a global install path.
**Why:** The project uses a local-git gstack install at `apps/readest-app/.claude/skills/gstack`. Previous mistakes upgraded a global copy while the project's local copy stayed outdated.
**How to apply:** When `/gstack-upgrade` is invoked, ensure the `cd` and `git reset --hard origin/main && ./setup` happen inside the project's `.claude/skills/gstack` directory.
@@ -0,0 +1,11 @@
---
name: Always use a new branch for new PRs
description: Each new PR/issue should get its own fresh branch from main, never reuse an existing feature branch
type: feedback
---
Always create a new branch from main for each new PR or issue. Never reuse an existing feature branch for unrelated work.
**Why:** The user corrected this when a storage fix was committed on the `feat/full-sync-annotations` branch instead of a dedicated branch. Mixing unrelated changes on the same branch makes PRs harder to review and manage.
**How to apply:** Before committing fixes, create a new branch like `fix/<topic>` from `origin/main`. Only reuse a branch if the work is directly related to that branch's existing purpose.
@@ -0,0 +1,11 @@
---
name: Always rebase before PR
description: Rebase to origin/main before creating pull requests
type: feedback
---
Always rebase the branch onto origin/main before creating a pull request.
**Why:** The user wants PRs to be up-to-date with main to avoid merge conflicts and keep a clean history.
**How to apply:** Before running `gh pr create`, always run `git fetch origin && git rebase origin/main` first. If there are conflicts, resolve them before proceeding.
@@ -0,0 +1,70 @@
# Layout & UI Fixes Reference
## Safe Area Insets
### Architecture
- Native plugins push inset values: iOS (`NativeBridgePlugin.swift`), Android (`NativeBridgePlugin.kt`)
- `useSafeAreaInsets` hook (`src/hooks/useSafeAreaInsets.ts`) reads and caches values
- Components use `gridInsets` for positioning relative to safe areas
- CSS: `env(safe-area-inset-top/bottom/left/right)` for CSS-level insets
### Common Issues
- **Stale insets after system UI change** (#3469): Call `onUpdateInsets()` after `setSystemUIVisibility()`
- **iPad sidebar insets wrong** (#3395): Different inset handling needed for sidebar vs main view
- **Android nav bar overlap** (#3466): Use `calc(env(safe-area-inset-bottom) + 16px)` for Android bottom padding
- **Zoom controls behind status bar** (#3426): Pass `gridInsets` through component chain, use `Math.max(gridInsets.top, statusBarHeight)`
### Rules (see also `docs/safe-area-insets.md`)
- Always pass `gridInsets` to overlay/floating components near screen edges
- On Android, account for system navigation bar with `env(safe-area-inset-bottom)`
- After toggling system UI visibility, force-refresh insets via `onUpdateInsets()`
## Z-Index Hierarchy
- Navigation buttons: `z-10` (when visible)
- Annotation nav bar: `z-10` (reduced from z-30 in #3386)
- TTS control button: ensure above page nav buttons
- Floating overlays: check against `gridInsets` positioning
## macOS Traffic Lights
- Managed by `trafficLightStore.ts` and `HeaderBar.tsx`
- **Fullscreen check required** (#3129): `await currentWindow.isFullscreen()` before hiding
- **Timeout for visibility toggle** (#3488): Use 100ms delay to prevent flickering
- **Sidebar interaction** (#3488): Check `getIsSideBarVisible()` before hiding traffic lights
- Never hide traffic lights when sidebar is open
## Touch/Input Issues
- **Slider hit area on iOS** (#3382): Use min-h-12, strip browser appearance with CSS
- **Context menu on macOS** (#3324): 100ms delay before `onContextMenu()` to let pointer events complete
- **Swipe sensitivity** (#3310): Use average velocity (distance/time) instead of instantaneous velocity for non-animated paging
- **Touchpad natural scrolling** (#3127): Respect system natural scrolling setting in `usePagination.ts`
## Dialog/Menu Layout
- **Dialog header** (#3352): Use `px-2 sm:pe-3 sm:ps-2` padding to align with border radius
- **Settings alignment** (#3151): Use `Menu` component instead of raw `div` for consistent styling
- **Dropdown for screen readers** (#3035): Use `DropdownContext` with overlay dismiss, not blur-based closing
## Component-Specific Fixes
### HeaderBar.tsx
- Traffic light visibility management
- Sidebar toggle persistent position (#3193)
- Library button placement
### PageNavigationButtons.tsx
- z-10 when visible (#3201)
- Always shown for screen readers (#3036)
- Toggle via `showPageNavButtons` setting
### ProgressInfo.tsx
- Use physical `page`/`pages` from renderer, not estimated values (#3213, #3200)
- CSS classes: `time-left-label`, `pages-left-label`, `progress-info-label` (#3343)
### ReadingRuler.tsx
- Remove `containerStyle` from overlay so dimmed area covers full screen (#3304)
### NavigationBar.tsx
- Handle `gridInsets` internally, not via pre-computed `navPadding` (#3466)
### ContentNavBar.tsx (annotation search results)
- Floating buttons with drop shadow, not full-width bar (#3386)
- z-10 z-index
@@ -0,0 +1,85 @@
# Platform Compatibility Fixes Reference
## Android
### WebView API Issues
- **`navigator.getGamepads()`** returns null on older WebView (#3245): Always null-check before `.some()`
- **`CompressionStream`** unavailable on some Android WebView versions (#3255): Add fallback zip compression path
- **Annotation tools unresponsive** (#3225): Don't call `makeSelection()` immediately on pointer-up; let popup flow complete naturally
- **Safe inset updates** (#3469): Call `onUpdateInsets()` after `setSystemUIVisibility()`
- **Navigation bar overlap** (#3466): Use `calc(env(safe-area-inset-bottom) + 16px)` for bottom padding
### General Android Rules
- Test with older WebView versions (97+)
- Always check API availability before calling Web APIs
- Touch event handling differs from iOS - avoid premature re-selection
## iOS
### Common Issues
- **Slider touch dead zones** (#3382): Strip native appearance, use larger hit areas (min-h-12)
- **Safe area insets stale** (#3395): Native Swift plugin must push updated insets
- **Section content caching** (#3242, #3206): Don't cache section content in foliate-js when updating subitems; cached content retains stale styles after mode switch
- **CompressionStream** (#3255): Also broken on iOS 15.x; zip.js has its own native API disable
- **zip.js native API** (#3170): Disable native `CompressionStream`/`DecompressionStream` on iOS 15.x
### iOS-Specific Code
- `src-tauri/plugins/tauri-plugin-native-bridge/ios/Sources/NativeBridgePlugin.swift`
- Slider CSS: `-webkit-appearance: none; appearance: none` in globals.css
- `useSafeAreaInsets.ts` hook
## macOS
### Traffic Lights (Window Controls)
- Check `isFullscreen()` before hiding (#3129)
- Use timeouts (100ms) for visibility transitions (#3488)
- Don't hide when sidebar is open (#3488)
### Input Issues
- **Context menu steals event loop** (#3324): 100ms setTimeout before calling menu.popup()
- **Touchpad natural scrolling** (#3127): Respect system setting in `usePagination.ts`
- **Two-finger swipe** (#3127): Support trackpad two-finger swipe for pagination
### macOS-Specific Code
- `src-tauri/src/macos/` - Platform-specific Rust code
- `src/store/trafficLightStore.ts`
- `src/hooks/useTrafficLight.ts`
## Linux
### WebKitGTK Issues
- **View Transitions API unsupported** (#3417): Feature-detect `document.startViewTransition` before calling
- Use `useAppRouter.ts` to avoid transitions on Linux
## E-ink Devices
### Legibility Issues
- **Low contrast colors** (#3258): Use `not-eink:` Tailwind variant prefix for colors/opacity
- **Links invisible** (#3258): Don't apply `text-primary` (blue) on e-ink; use default text color
- **Opacity too low** (#3258): Don't apply `opacity-60`/`opacity-75` on e-ink devices
- **Highlight visibility** (#3299): Use foreground color for highlights in dark mode e-ink
### E-ink CSS Pattern
```
// Instead of:
className="text-primary opacity-60"
// Use:
className="not-eink:text-primary not-eink:opacity-60"
```
## Docker/Self-Hosting
- **Missing submodules** (#3233): Run `git submodule update --init --recursive` before build
- Simplecc WASM module must be initialized
## OPDS
- **Non-ASCII credentials** (#3436): Use `TextEncoder` + manual Base64 instead of `btoa()`
- **Author parsing** (#3120): Handle varied metadata structures in OPDS 2.0 feeds
- **Responsive layout** (#3418): Ensure catalog and download button layout works on small screens
## Cross-Platform Testing Checklist
1. Android (old WebView + current)
2. iOS (15.x + current)
3. macOS (traffic lights, trackpad)
4. Linux (WebKitGTK)
5. E-ink devices (contrast, colors)
6. Web (CloudFlare Workers deployment)
@@ -0,0 +1,50 @@
# TTS (Text-to-Speech) Fixes Reference
## Architecture
### Key Components
- `TTSController` (`src/services/tts/TTSController.ts`) - Core state machine
- `EdgeTTSClient` (`src/services/tts/EdgeTTSClient.ts`) - Edge TTS provider
- `useTTSControl` hook (`src/app/reader/hooks/useTTSControl.ts`) - React integration
- `useTTSMediaSession` hook (`src/app/reader/hooks/useTTSMediaSession.ts`) - Media controls
### Section-Aware TTS Model
TTS tracks its own section independently from the view via `#ttsSectionIndex`:
- `#initTTSForSection()` - Creates TTS document for a section without changing the view
- `#initTTSForNextSection()` / `#initTTSForPrevSection()` - Navigate TTS across sections
- `#getHighlighter()` - Only returns highlighter if view section matches TTS section
- `onSectionChange` callback - Notifies UI when TTS crosses section boundary
- Highlights use CFI strings (not raw Range objects) for cross-section compatibility
### State Management Pitfalls
1. **`#ttsSectionIndex` must match view section for highlights to work**
- If `-1`, all highlight calls are suppressed
- `shutdown()` sets it to `-1` but must also null out `this.view.tts`
2. **Guards/Refs that block re-entry:**
- The old `ttsOnRef` guard blocked TTS restart from annotations (removed in #3292)
- `view.tts` reference surviving shutdown blocked re-initialization (#3400)
3. **Timeouts that fire after pause:**
- Edge TTS had a safety timeout that advanced sentences even when paused (#3244)
- Solution: removed the entire `ontimeupdate` safety timeout mechanism
## Fix History
| Issue | Problem | Root Cause | Fix |
|-------|---------|------------|-----|
| #3100 | TTS scrolls too far | TTS coupled to view section | Added `#ttsSectionIndex`, "Back to TTS Location" button |
| #3198 | TTS doesn't follow to next section | No `onSectionChange` callback | Added section change notification, extracted hooks |
| #3244 | Paused TTS advances | Safety timeout fires after pause | Removed `ontimeupdate` timeout mechanism |
| #3291 | TTS fails without lang attribute | Invalid SSML from missing lang | Set lang/xml:lang on html element from `ttsLang` |
| #3292 | Can't restart TTS from annotation | `ttsOnRef` blocks re-entry | Removed the guard ref entirely |
| #3400 | TTS highlight stops after restart | `view.tts` not nulled on shutdown | Added `this.view.tts = null` in `shutdown()` |
## Debugging TTS Issues
1. **TTS doesn't start:** Check `#initTTSForSection()` - does `view.tts.doc === doc` shortcut early?
2. **No highlights:** Check `#ttsSectionIndex` matches view's section index
3. **Advances when paused:** Look for setTimeout/timer callbacks that bypass pause state
4. **Can't restart:** Check for refs/guards that prevent re-entry into speak handlers
5. **Fails on some chapters:** Check if chapter has lang attribute and XHTML namespace
6. **SSML errors:** Check `src/utils/ssml.ts` for proper namespace/lang handling
@@ -0,0 +1,5 @@
## Test-First Development
- Always write a failing unit test **before** implementing a fix.
- Run the test to confirm it reproduces the bug or fails as expected, then apply the fix and verify the test passes.
- Run the full test suite (`pnpm test`) after changes to ensure no regressions.
@@ -0,0 +1,5 @@
## TypeScript
- Never use the `any` type. Use `unknown`, proper types, or generics instead.
- Strict mode is enabled. Target is ES2022.
- Unused vars prefixed with `_` are allowed (ESLint configured).
@@ -0,0 +1,8 @@
## Verification (done-conditions)
Before marking work complete, all applicable checks must pass:
1. `pnpm test` — unit tests
2. `pnpm lint` — ESLint
3. `pnpm fmt:check` — Rust format check (only when `src-tauri/` files changed)
4. `pnpm clippy:check` — Rust lint (only when `src-tauri/` files changed)
+1 -1
View File
@@ -3,7 +3,7 @@ PDFJS_FONTS_PATH=../../packages/foliate-js/node_modules/pdfjs-dist
PDFJS_STYLE_PATH=../../packages/foliate-js/vendor/pdfjs
NEXT_PUBLIC_DEFAULT_POSTHOG_URL_BASE64="aHR0cHM6Ly91cy5pLnBvc3Rob2cuY29t"
NEXT_PUBLIC_DEFAULT_POSTHOG_KEY_BASE64="cGhjX2ViNXowbVRxWm8yZm5YYnZGNmE3bFh5TThpTmRSNTNsR1A3VFM3VGh4S08="
NEXT_PUBLIC_DEFAULT_POSTHOG_KEY_BASE64="cGhjX0x3ekhZRWtsZUVub3ZSc05ZQlRpTVRTV2MyS1NUOFdZMzBIWWFhN0ZPa1IK"
NEXT_PUBLIC_DEFAULT_SUPABASE_URL_BASE64="aHR0cHM6Ly9yZWFkZXN0LnN1cGFiYXNlLmNv"
NEXT_PUBLIC_DEFAULT_SUPABASE_KEY_BASE64="ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKemRYQmhZbUZ6WlNJc0luSmxaaUk2SW5aaWMzbDRablZ6YW1weFpIaHJhbkZzZVhOaklpd2ljbTlzWlNJNkltRnViMjRpTENKcFlYUWlPakUzTXpReE1qTTJOekVzSW1WNGNDSTZNakEwT1RZNU9UWTNNWDAuM1U1VXFhb3VfMVNnclZlMWVvOXJBcGMwdUtqcWhwUWRVWGh2d1VIbVVmZw=="
+2
View File
@@ -28,3 +28,5 @@ S3_ACCESS_KEY_ID=PLACE_HOLDER
S3_SECRET_ACCESS_KEY=PLACE_HOLDER
S3_BUCKET_NAME=PLACE_HOLDER
S3_REGION=PLACE_HOLDER
TEMP_STORAGE_PUBLIC_BUCKET_NAME=PLACE_HOLDER
+3 -1
View File
@@ -1 +1,3 @@
NEXT_PUBLIC_APP_PLATFORM=tauri
NEXT_PUBLIC_APP_PLATFORM=tauri
DBUS_ID=com.bilingify.readest
+2
View File
@@ -0,0 +1,2 @@
NEXT_PUBLIC_APP_PLATFORM=tauri
AI_GATEWAY_API_KEY=your_key_here
+3
View File
@@ -0,0 +1,3 @@
NEXT_PUBLIC_APP_PLATFORM=web
AI_GATEWAY_API_KEY=your_key_here
NEXT_PUBLIC_AI_GATEWAY_API_KEY=your_key_here
+9
View File
@@ -8,6 +8,7 @@
# testing
/coverage
.test-sandbox-node/
# next.js
/.next/
@@ -48,6 +49,9 @@ tauri.*.conf.json
*.tsbuildinfo
next-env.d.ts
# eslint
.eslintcache
#generated
src-tauri/gen
@@ -60,3 +64,8 @@ src-tauri/gen
/public/fallback-*.js
/public/swe-worker-*.js
/dist/
.claude/settings.local.json
.claude/skills
+91
View File
@@ -0,0 +1,91 @@
## Project Overview
Readest is a cross-platform ebook reader built as a **Next.js 16 + Tauri v2** hybrid app. It's part of a pnpm monorepo at `/apps/readest-app/`. The app runs on web (CloudFlare Workers), desktop (macOS/Windows/Linux via Tauri), and mobile (iOS/Android via Tauri).
## Common Commands
```bash
# Development
pnpm dev-web # Web-only dev server (no Rust compilation needed)
pnpm tauri dev # Desktop dev with Tauri (compiles Rust backend)
# Building
pnpm build # Build Next.js for Tauri
pnpm build-web # Build Next.js for web deployment
# Testing (see [docs/testing.md](docs/testing.md) for full details)
pnpm test # Unit tests (vitest + jsdom)
pnpm test -- src/__tests__/utils/misc.test.ts # Run a single test file
pnpm test -- --watch # Watch mode
pnpm test:browser # Browser tests (Chromium via Playwright)
pnpm tauri:dev:test # Start Tauri app with webdriver
pnpm test:tauri # Run Tauri integration tests
# Linting & Formatting
pnpm lint # Biome (linter) + tsgo (type check)
pnpm format # Prettier (runs from monorepo root)
pnpm format:check # Check formatting without writing
# Rust
pnpm fmt:check # Check formatting Rust code (src-tauri)
pnpm clippy:check # Lint Rust code (src-tauri)
```
### Source Layout
| Directory | Purpose |
| ----------------- | ------------------------------------------------------------- |
| `src/app/` | Next.js App Router pages and API routes |
| `src/components/` | React components (reader, settings, library, assistant, etc.) |
| `src/services/` | Business logic: TTS, translators, OPDS, sync, AI, metadata |
| `src/store/` | Zustand state stores |
| `src/hooks/` | Custom React hooks |
| `src/libs/` | Document loaders, payment, storage, sync |
| `src/utils/` | Pure utility functions |
| `src/types/` | TypeScript type definitions |
| `src/context/` | React Context providers (Auth, Env, Sync, etc.) |
| `src/workers/` | Web Workers for background tasks |
| `src-tauri/` | Rust backend: Tauri plugins, platform-specific code |
### Path Aliases (tsconfig)
- `@/*``./src/*`
- `@/components/ui/*``./src/components/primitives/*`
### Rust Backend (`src-tauri/`)
Platform-specific code lives in `src-tauri/src/{macos,windows,android,ios}/`. Custom Tauri plugins are in `src-tauri/plugins/`.
## Project Rules
Rules are in `.claude/rules/`: test-first, typescript, verification.
### i18n
See [docs/i18n.md](docs/i18n.md) for the key-as-content translation approach, `stubTranslation` usage in non-React modules, and extraction workflow.
### Safe Area Insets
See [docs/safe-area-insets.md](docs/safe-area-insets.md) for rules on handling top/bottom insets for UI elements near screen edges.
## Web Browsing & QA (gstack)
For all web browsing, QA testing, and site interaction, use the `/browse` skill from gstack. **Never use `mcp__claude-in-chrome__*` tools directly.**
Available gstack skills:
- `/plan-ceo-review` — CEO/founder-mode plan review
- `/plan-eng-review` — Eng manager-mode plan review
- `/plan-design-review` — Designer's eye review of a live site
- `/design-consultation` — Design system consultation
- `/review` — Pre-landing PR review
- `/ship` — Ship workflow (merge, test, review, bump, PR)
- `/browse` — Fast headless browser for QA and site interaction
- `/qa` — QA test and fix bugs
- `/qa-only` — QA report only (no fixes)
- `/qa-design-review` — Designer's eye QA with fixes
- `/setup-browser-cookies` — Import cookies for authenticated testing
- `/retro` — Weekly engineering retrospective
- `/document-release` — Post-ship documentation update
If gstack skills aren't working, run `cd .claude/skills/gstack && ./setup` to build the binary and register skills.
+1
View File
@@ -0,0 +1 @@
AGENTS.md
+125
View File
@@ -0,0 +1,125 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "ignoreUnknown": true },
"formatter": { "enabled": false },
"assist": { "enabled": false },
"css": { "linter": { "enabled": false } },
"linter": {
"enabled": true,
"includes": [
"**",
"!.next/**",
"!.open-next/**",
"!.wrangler/**",
"!.claude/**",
"!dist/**",
"!out/**",
"!build/**",
"!public/**",
"!src-tauri/**",
"!next-env.d.ts",
"!i18next-scanner.config.cjs"
],
"rules": {
"recommended": true,
"a11y": {
"recommended": true,
"useKeyWithClickEvents": "off",
"useKeyWithMouseEvents": "off",
"noSvgWithoutTitle": "off",
"noLabelWithoutControl": "off",
"useSemanticElements": "off",
"noAriaHiddenOnFocusable": "off",
"noInteractiveElementToNoninteractiveRole": "off",
"noNoninteractiveElementToInteractiveRole": "off",
"noNoninteractiveElementInteractions": "off",
"noStaticElementInteractions": "off",
"noNoninteractiveTabindex": "off",
"useButtonType": "off",
"useAriaPropsSupportedByRole": "off",
"useFocusableInteractive": "off",
"noAutofocus": "off"
},
"complexity": {
"noForEach": "off",
"noStaticOnlyClass": "off",
"noUselessSwitchCase": "off",
"noUselessFragments": "off",
"noUselessCatch": "off",
"useLiteralKeys": "off",
"useOptionalChain": "off",
"noThisInStatic": "off",
"useArrowFunction": "off",
"noUselessEscapeInRegex": "off"
},
"correctness": {
"noUnusedVariables": "warn",
"noUnusedImports": "error",
"useExhaustiveDependencies": "off",
"useHookAtTopLevel": "error",
"useJsxKeyInIterable": "error",
"noChildrenProp": "error",
"noNextAsyncClientComponent": "warn",
"noSwitchDeclarations": "off",
"noUndeclaredVariables": "off",
"noEmptyCharacterClassInRegex": "off",
"useParseIntRadix": "off",
"noEmptyPattern": "off"
},
"nursery": {
"noBeforeInteractiveScriptOutsideDocument": "warn",
"noDuplicateEnumValues": "error",
"noSyncScripts": "warn",
"useInlineScriptId": "error"
},
"performance": {
"noImgElement": "off",
"noUnwantedPolyfillio": "warn",
"useGoogleFontPreconnect": "warn"
},
"security": {
"noBlankTarget": "off",
"noDangerouslySetInnerHtmlWithChildren": "off",
"noDangerouslySetInnerHtml": "off"
},
"style": {
"noNonNullAssertion": "off",
"useImportType": "off",
"noParameterAssign": "off",
"useDefaultParameterLast": "off",
"noUselessElse": "off",
"noHeadElement": "warn",
"noCommonJs": "off",
"useFilenamingConvention": "off",
"useNamingConvention": "off",
"noUnusedTemplateLiteral": "off",
"useTemplate": "off",
"useExponentiationOperator": "off",
"useNodejsImportProtocol": "off"
},
"suspicious": {
"noExplicitAny": "error",
"noArrayIndexKey": "off",
"noAssignInExpressions": "off",
"noDoubleEquals": "off",
"noDocumentImportInPage": "error",
"noHeadImportInDocument": "error",
"useGoogleFontDisplay": "warn",
"noCommentText": "error",
"noDuplicateJsxProps": "error",
"noAsyncPromiseExecutor": "off",
"noImplicitAnyLet": "off",
"noControlCharactersInRegex": "off",
"noEmptyBlockStatements": "off",
"useIterableCallbackReturn": "off",
"noGlobalIsNan": "off",
"noConfusingVoidType": "off",
"noConstEnum": "off"
}
}
},
"javascript": {
"globals": ["React"]
}
}
+22
View File
@@ -0,0 +1,22 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/utils",
"ui": "@/components/ui",
"lib": "@/libs",
"hooks": "@/hooks"
},
"registries": {}
}
+48
View File
@@ -0,0 +1,48 @@
## i18n Guide
Readest uses a **key-as-content** approach — English strings are the translation keys. The English locale (`en/translation.json`) is empty because keys serve as content. Other locales contain actual translations.
### In React Components
```tsx
import { useTranslation } from '@/hooks/useTranslation';
const _ = useTranslation();
_('Progress synced');
```
### In Non-React Modules
Two-step process:
**1. Declaration** — Use `stubTranslation` to mark strings for scanner extraction (returns key as-is, does NOT translate):
```ts
import { stubTranslation as _ } from '@/utils/misc';
// These calls only register keys for extraction
_('Reveal in Finder');
_('Reveal in Explorer');
```
**2. Usage** — In the React component that consumes the value, apply the real `_()` from `useTranslation`:
```tsx
const _ = useTranslation();
const label = _(getRevealLabel()); // translates at runtime
```
### Extraction & Translation
```bash
pnpm i18n:extract # Scans codebase, adds new keys with __STRING_NOT_TRANSLATED__
```
- Translation files: `public/locales/<locale>/translation.json`
- Only `_('KEY')` and `_('KEY', options)` patterns are recognized by i18next-scanner
### Rules
- `stubTranslation` is for extraction only — always apply `_()` from `useTranslation` in the component for runtime translation.
- Fallback: when no translation exists, the English key itself is displayed.
- Error messages: register keys with `stubTranslation` in utility modules (e.g. `src/services/errors.ts`), return the English key from helpers, wrap with `_()` in the component.
+52
View File
@@ -0,0 +1,52 @@
## Safe Area Insets
The app runs on devices with notches, status bars, and rounded corners (iOS, Android). UI elements near screen edges must account for safe area insets to avoid being obscured.
### Key Concepts
- **`gridInsets: Insets`** — Per-view insets derived from view settings (header/footer visibility, margins). Calculated by `getViewInsets()` in `src/utils/insets.ts`. Passed as a prop from `BooksGrid` → child components.
- **`statusBarHeight: number`** — OS status bar height (default 24px). Stored in `themeStore`.
- **`systemUIVisible: boolean`** — Whether the system UI (status bar, navigation bar) is currently shown. Stored in `themeStore`.
- **`appService?.hasSafeAreaInset`** — Whether the platform requires safe area handling (mobile devices).
### Top Inset Rules
For UI elements anchored to the **top** of the screen (headers, close buttons, overlays):
```tsx
// When system UI is visible, use the larger of gridInsets.top and statusBarHeight
// When system UI is hidden, use gridInsets.top alone
style={{
marginTop: systemUIVisible
? `${Math.max(gridInsets.top, statusBarHeight)}px`
: `${gridInsets.top}px`,
}}
```
For containers that need safe area padding at the top:
```tsx
style={{
paddingTop: appService?.hasSafeAreaInset ? `${gridInsets.top}px` : '0px',
}}
```
### Bottom Inset Rules
For UI elements anchored to the **bottom** of the screen (footer bars, controls, progress indicators), use `gridInsets.bottom * 0.33` as padding — a fraction of the full inset since bottom bars don't need as much clearance as the home indicator area:
```tsx
style={{
paddingBottom: appService?.hasSafeAreaInset ? `${gridInsets.bottom * 0.33}px` : 0,
}}
```
### Passing `gridInsets`
When creating overlay components (image viewers, table viewers, zoom controls, etc.), always pass `gridInsets` as a prop so they can position their controls correctly:
```tsx
<ImageViewer gridInsets={gridInsets} ... />
<TableViewer gridInsets={gridInsets} ... />
<ZoomControls gridInsets={gridInsets} ... />
```
+110
View File
@@ -0,0 +1,110 @@
# Testing
Readest uses three test tiers, all powered by [Vitest](https://vitest.dev/).
## Unit Tests (`pnpm test`)
Runs tests in a **jsdom** environment. No browser or Tauri runtime required.
```bash
pnpm test # Run all unit tests
pnpm test -- src/__tests__/utils/misc.test.ts # Run a single file
pnpm test -- --watch # Watch mode
```
- **Config:** `vitest.config.mts`
- **Pattern:** `src/**/*.test.ts` (excludes `*.browser.test.ts` and `*.tauri.test.ts`)
- **Environment:** jsdom
- **Use for:** Pure logic, utilities, services that don't need real browser APIs or Tauri IPC.
## Browser Tests (`pnpm test:browser`)
Runs tests in a **real Chromium** browser via Playwright. Required for code that depends on Web Workers, SharedArrayBuffer, OPFS, or other browser-only APIs.
```bash
pnpm test:browser
```
- **Config:** `vitest.browser.config.mts`
- **Pattern:** `src/**/*.browser.test.ts`
- **Browser:** Chromium (headless, via `@vitest/browser-playwright`)
- **Use for:** WASM modules (e.g. `@tursodatabase/database-wasm`), Web Worker integration, browser-specific storage APIs.
## Tauri Integration Tests (`pnpm test:tauri`)
Runs Vitest tests **inside the Tauri WebView**, with access to Tauri IPC and native plugin commands. Tests execute in the actual app environment.
### Step 1: Start the Tauri App
In one terminal, start the app with the `webdriver` feature enabled:
```bash
pnpm tauri:dev:test # Dev mode (uses tauri dev server, faster iteration)
pnpm tauri:build:test # Debug release build (closer to production)
```
These commands compile the Rust backend with `--features webdriver`, which:
- Includes `tauri-plugin-webdriver` (embeds a W3C WebDriver server on port 4445)
- Adds a runtime capability granting plugin permissions to remote URLs (`http://127.0.0.1:*`), so Vitest's browser-mode iframe can call Tauri IPC
Keep this running while you run tests.
### Step 2: Run Tests
In another terminal:
```bash
pnpm test:tauri
```
Vitest connects directly to the embedded WebDriver server (port 4445) in the running Tauri app and executes tests inside its WebView.
- **Config:** `vitest.tauri.config.mts`
- **Pattern:** `src/**/*.tauri.test.ts`
- **Browser provider:** `@vitest/browser-webdriverio` (connects to port 4445)
- **Use for:** Tauri plugin commands (turso, native-tts, etc.), native filesystem, Tauri IPC.
### Writing Tauri Tests
Tests access Tauri IPC via a shared helper:
```typescript
import { invoke } from '../tauri/tauri-invoke';
it('calls a plugin command', async () => {
const result = await invoke('plugin:turso|load', { options: { path: 'sqlite::memory:' } });
expect(result).toBeDefined();
});
```
The `invoke()` helper accesses `window.top.__TAURI_INTERNALS__` (Vitest runs in an iframe, Tauri injects IPC into the main frame).
**Limitations:** Only custom invoke commands and plugin commands listed in the webdriver capability work. Standard Tauri JS APIs (e.g. `@tauri-apps/api`) that rely on `URL: local` may not work from the Vitest iframe.
## E2E Tests (WDIO)
Full end-to-end tests using WebDriverIO, for UI-level testing against the running Tauri app. Same two-step workflow as Tauri integration tests.
```bash
# Terminal 1: start the app (same as for Tauri integration tests)
pnpm tauri:dev:test
# Terminal 2: run E2E tests
pnpm test:e2e
```
- **Config:** `wdio.conf.ts`
- **Pattern:** `e2e/**/*.e2e.ts`
- **Framework:** Mocha (via `@wdio/mocha-framework`)
- **Connects to:** port 4445 (embedded WebDriver server)
- **Use for:** UI interaction tests, window management, navigation flows.
## Test File Naming
| Suffix | Runner | Environment |
| ------------------- | ------------------- | --------------------- |
| `*.test.ts` | `pnpm test` | jsdom |
| `*.browser.test.ts` | `pnpm test:browser` | Chromium (Playwright) |
| `*.tauri.test.ts` | `pnpm test:tauri` | Tauri WebView |
| `*.e2e.ts` | `pnpm test:e2e` | Tauri app (WDIO) |
+123
View File
@@ -0,0 +1,123 @@
describe('Readest App Launch', () => {
it('should have a visible body element', async () => {
const body = await $('body');
await body.waitForDisplayed({ timeout: 10000 });
expect(await body.isDisplayed()).toBe(true);
});
it('should have the correct window handle', async () => {
const handle = await browser.getWindowHandle();
expect(handle).toBeTruthy();
});
it('should return the page source', async () => {
const source = await browser.getPageSource();
expect(source).toContain('html');
});
});
describe('Library Page', () => {
it('should navigate to the library page', async () => {
const url = await browser.getUrl();
expect(url).toMatch(/library|localhost/);
});
it('should display the library container', async () => {
const library = await $('[aria-label="Your Library"]');
await library.waitForExist({ timeout: 15000 });
expect(await library.isExisting()).toBe(true);
});
it('should display the library header', async () => {
const header = await $('[aria-label="Library Header"]');
await header.waitForExist({ timeout: 10000 });
expect(await header.isExisting()).toBe(true);
});
it('should display the bookshelf area', async () => {
const bookshelf = await $('[aria-label="Bookshelf"]');
await bookshelf.waitForExist({ timeout: 10000 });
expect(await bookshelf.isExisting()).toBe(true);
});
it('should have a search input', async () => {
const searchInput = await $('.search-input');
await searchInput.waitForExist({ timeout: 10000 });
expect(await searchInput.isExisting()).toBe(true);
});
it('should allow typing in the search input', async () => {
const searchInput = await $('.search-input');
await searchInput.waitForDisplayed({ timeout: 10000 });
await searchInput.setValue('test search');
const value = await searchInput.getValue();
expect(value).toBe('test search');
});
it('should show the clear search button after typing', async () => {
const clearBtn = await $('[aria-label="Clear Search"]');
await clearBtn.waitForExist({ timeout: 5000 });
expect(await clearBtn.isExisting()).toBe(true);
});
it('should clear the search input when clear button is clicked', async () => {
const clearBtn = await $('[aria-label="Clear Search"]');
await clearBtn.click();
const searchInput = await $('.search-input');
const value = await searchInput.getValue();
expect(value).toBe('');
});
it('should have a select books button', async () => {
const selectBtn = await $('[aria-label="Select Books"]');
await selectBtn.waitForExist({ timeout: 10000 });
expect(await selectBtn.isExisting()).toBe(true);
});
it('should have an import books button', async () => {
const importBtn = await $('[aria-label="Import Books"]');
await importBtn.waitForExist({ timeout: 10000 });
expect(await importBtn.isExisting()).toBe(true);
});
});
describe('Window Management', () => {
it('should return the window size', async () => {
const size = await browser.getWindowSize();
expect(size.width).toBeGreaterThan(0);
expect(size.height).toBeGreaterThan(0);
});
});
describe('JavaScript Execution', () => {
it('should execute JavaScript in the app context', async () => {
const result = await browser.execute(() => {
return document.readyState;
});
expect(result).toBe('complete');
});
it('should access the document title via JS', async () => {
const title = await browser.execute(() => {
return document.title;
});
expect(title).toContain('Readest');
});
it('should detect the app platform globals', async () => {
const hasCLIAccess = await browser.execute(() => {
return (window as unknown as Record<string, unknown>).__READEST_CLI_ACCESS === true;
});
expect(hasCLIAccess).toBe(true);
});
});
describe('Navigation', () => {
it('should navigate back to library after visiting another route', async () => {
const currentUrl = await browser.getUrl();
await browser.url(currentUrl.replace(/\/[^/]*$/, '/library'));
const library = await $('[aria-label="Your Library"]');
await library.waitForExist({ timeout: 15000 });
expect(await library.isExisting()).toBe(true);
});
});
+11
View File
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"types": ["mocha", "@wdio/globals/types"]
},
"include": ["./**/*.ts"]
}
-13
View File
@@ -1,13 +0,0 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
export default [...compat.extends("next/core-web-vitals", "next/typescript")];
+588
View File
@@ -0,0 +1,588 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytemuck"
version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "derive_arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "directories-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "flate2"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [
"crc32fast",
"libz-rs-sys",
"miniz_oxide",
]
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gif"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f954a9e9159ec994f73a30a12b96a702dde78f5547bcb561174597924f7d4162"
dependencies = [
"color_quant",
"weezl",
]
[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "image"
version = "0.25.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
dependencies = [
"bytemuck",
"byteorder-lite",
"color_quant",
"gif",
"image-webp",
"moxcms",
"num-traits",
"png",
"zune-core",
"zune-jpeg",
]
[[package]]
name = "image-webp"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
dependencies = [
"byteorder-lite",
"quick-error",
]
[[package]]
name = "indexmap"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "libredox"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
dependencies = [
"bitflags",
"libc",
]
[[package]]
name = "libz-rs-sys"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd"
dependencies = [
"zlib-rs",
]
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "md5"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
name = "moxcms"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80986bbbcf925ebd3be54c26613d861255284584501595cf418320c078945608"
dependencies = [
"num-traits",
"pxfm",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "png"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
dependencies = [
"bitflags",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pxfm"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3502d6155304a4173a5f2c34b52b7ed0dd085890326cb50fd625fdf39e86b3b"
dependencies = [
"num-traits",
]
[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_users"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "syn"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "weezl"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
dependencies = [
"windows-collections",
"windows-core",
"windows-future",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
dependencies = [
"windows-core",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-future"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
dependencies = [
"windows-core",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-numerics"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
dependencies = [
"windows-core",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-threading"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
dependencies = [
"windows-link",
]
[[package]]
name = "windows_thumbnail"
version = "0.1.0"
dependencies = [
"anyhow",
"base64",
"directories-next",
"image",
"md5",
"once_cell",
"windows",
"windows-core",
"zip",
]
[[package]]
name = "zip"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b"
dependencies = [
"arbitrary",
"crc32fast",
"flate2",
"indexmap",
"memchr",
"zopfli",
]
[[package]]
name = "zlib-rs"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2"
[[package]]
name = "zopfli"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249"
dependencies = [
"bumpalo",
"crc32fast",
"log",
"simd-adler32",
]
[[package]]
name = "zune-core"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "111f7d9820f05fd715df3144e254d6fc02ee4088b0644c0ffd0efc9e6d9d2773"
[[package]]
name = "zune-jpeg"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6fb7703e32e9a07fb3f757360338b3a567a5054f21b5f52a666752e333d58e"
dependencies = [
"zune-core",
]
@@ -0,0 +1,31 @@
[package]
name = "windows_thumbnail"
version = "0.1.0"
edition = "2021"
publish = false
[workspace]
[lib]
name = "windows_thumbnail"
path = "src/mod.rs"
crate-type = ["cdylib"]
[dependencies]
anyhow = "1"
base64 = "0.22"
directories-next = "2.0"
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "gif", "webp"] }
md5 = "0.8"
once_cell = "1.19"
zip = { version = "6.0", default-features = false, features = ["deflate"] }
windows = { version = "0.62", features = [
"Win32_Foundation",
"Win32_Graphics_Gdi",
"Win32_Security",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Registry",
"Win32_UI_Shell",
] }
windows-core = "0.62"
@@ -0,0 +1,134 @@
# Windows Thumbnail Provider for Readest
This crate provides Windows Explorer thumbnail support for eBook files when Readest is set as the default application.
## Features
- **Automatic Cover Extraction**: Extracts cover images from EPUB, MOBI, AZW, AZW3, FB2, CBZ, CBR files
- **Readest Branding**: Adds a small Readest icon overlay at the bottom-right corner
- **Smart Caching**: Caches generated thumbnails for faster subsequent loads
- **File Association Aware**: Only shows thumbnails when Readest is the default app for the file type
- **COM Integration**: Full Windows Shell extension implementation via `IThumbnailProvider`
## Supported Formats
| Format | Extension | Cover Source |
| ---------- | ----------------------- | ---------------------------- |
| EPUB | `.epub` | OPF manifest cover reference |
| MOBI/AZW | `.mobi`, `.azw`, `.prc` | EXTH cover offset |
| AZW3/KF8 | `.azw3`, `.kf8` | KF8 format cover |
| FB2 | `.fb2` | `<binary>` coverpage element |
| Comic Book | `.cbz`, `.cbr` | First image in archive |
| Plain Text | `.txt` | Generated placeholder |
## Building
### Library Only
```bash
cargo build --release
```
### COM DLL (for Windows Explorer integration)
```bash
cargo build --release --features com
```
### CLI Tool
```bash
cargo build --release --features cli
```
## Installation
The thumbnail provider DLL is automatically registered when Readest is installed via the NSIS installer.
### Manual Registration (for development)
```powershell
# Register the DLL
regsvr32 /s target\release\windows_thumbnail.dll
# Unregister the DLL
regsvr32 /s /u target\release\windows_thumbnail.dll
# Refresh Explorer to see changes
ie4uinit.exe -show
```
After registration, you may need to restart Windows Explorer or log out/in for changes to take effect.
## Usage (Development / Manual testing)
For local development and testing, build the Windows DLL (or the library) from the Readest Tauri app folder and register it manually. The legacy CLI test harness used to live in the separate `packages/tauri` workspace, but the thumbnail handler implementation now lives inside Readest's Tauri app.
Build the DLL (for Windows explorer integration):
```powershell
cd apps/readest-app/src-tauri
cargo build --release --manifest-path Cargo.toml --features com
```
The standalone CLI test harness is no longer distributed with the app. To test the thumbnail provider locally, build and register the DLL as shown above and use a small test harness that imports `readestlib`'s thumbnail code or use Explorer after registering the handler.
Manual registration for development (register the generated DLL):
```powershell
# Register the DLL
regsvr32 /s target\release\windows_thumbnail.dll
# Unregister the DLL
regsvr32 /s /u target\release\windows_thumbnail.dll
# Refresh Explorer to see changes
ie4uinit.exe -show
```
This generates a thumbnail with the Readest overlay at the specified size.
## Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ Windows Explorer │
├─────────────────────────────────────────────────────────────────┤
│ │ │
│ IThumbnailProvider ───┼──► ThumbnailProvider │
│ │ │ │
│ │ ▼ │
│ │ Check File Association │
│ │ (is Readest the default?) │
│ │ │ │
│ │ ▼ (if yes) │
│ │ Extract Cover Image │
│ │ │ │
│ │ ▼ │
│ │ Add Readest Overlay │
│ │ │ │
│ │ ▼ │
│ │ Return HBITMAP │
│ │ │
└─────────────────────────────────────────────────────────────────┘
```
## COM Details
- **CLSID**: `{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}`
- **Shell Thumbnail Handler GUID**: `{e357fccd-a995-4576-b01f-234630154e96}`
- **Threading Model**: Apartment
## How It Works
1. When Windows Explorer needs a thumbnail, it queries the registered shell extension
2. The COM DLL implements `IInitializeWithItem` to receive the file path
3. It checks if Readest.exe is the default application for that file type using `AssocQueryStringW`
4. If Readest is the default, it extracts the cover and generates the thumbnail
5. If Readest is NOT the default, it returns `S_FALSE` to let Windows use other handlers
This ensures thumbnails only appear for files the user has associated with Readest.
## License
MIT License - See LICENSE file for details.
@@ -0,0 +1,506 @@
/// Windows COM Thumbnail Provider for Readest
///
/// Implements IThumbnailProvider and IInitializeWithItem for Windows Shell integration.
/// This allows Windows Explorer to show book covers as thumbnails for eBook files.
///
/// **Important**: Thumbnails are only shown when Readest.exe is the default application
/// for the file type.
///
/// ## CLSID: {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}
use std::cell::UnsafeCell;
use std::ffi::c_void;
use std::path::PathBuf;
use std::sync::atomic::{AtomicIsize, AtomicU32, Ordering};
use windows::core::{IUnknown, Interface, GUID, HRESULT, PCWSTR, PWSTR};
use windows::Win32::Foundation::{
CLASS_E_NOAGGREGATION, E_FAIL, E_INVALIDARG, E_NOINTERFACE, HMODULE, S_FALSE, S_OK,
};
use windows::Win32::Graphics::Gdi::{
CreateDIBSection, BITMAPINFO, BITMAPINFOHEADER, BI_RGB, DIB_RGB_COLORS, HBITMAP,
};
use windows::Win32::System::Com::{CoTaskMemFree, IClassFactory, IClassFactory_Impl};
use windows::Win32::System::LibraryLoader::GetModuleFileNameW;
use windows::Win32::System::Registry::{
RegCloseKey, RegCreateKeyExW, RegDeleteTreeW, RegSetValueExW, HKEY, HKEY_CLASSES_ROOT,
KEY_WRITE, REG_OPTION_NON_VOLATILE, REG_SZ,
};
use windows::Win32::UI::Shell::{
AssocQueryStringW, IInitializeWithItem, IInitializeWithItem_Impl, IShellItem,
IThumbnailProvider, IThumbnailProvider_Impl, ASSOCF_NONE, ASSOCSTR_EXECUTABLE,
SIGDN_FILESYSPATH, WTSAT_ARGB, WTS_ALPHATYPE,
};
use windows_core::BOOL;
use windows_core::{implement, Ref};
use super::cached_thumbnail_for_path;
// ─────────────────────────────────────────────────────────────────────────────
// CLSID for Readest Thumbnail Provider
// ─────────────────────────────────────────────────────────────────────────────
/// CLSID: {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}
pub const CLSID_READEST_THUMBNAIL: GUID = GUID::from_u128(0xA1B2C3D4_E5F6_7890_ABCD_EF1234567890);
/// Supported file extensions
pub const SUPPORTED_EXTENSIONS: &[&str] = &[
".epub", ".mobi", ".azw", ".azw3", ".kf8", ".prc", ".fb2", ".cbz", ".cbr", ".txt",
];
// DLL reference counting
static DLL_REF_COUNT: AtomicU32 = AtomicU32::new(0);
static DLL_MODULE_PTR: AtomicIsize = AtomicIsize::new(0);
fn dll_add_ref() {
DLL_REF_COUNT.fetch_add(1, Ordering::SeqCst);
}
fn dll_release() {
DLL_REF_COUNT.fetch_sub(1, Ordering::SeqCst);
}
fn set_dll_module(h: HMODULE) {
DLL_MODULE_PTR.store(h.0 as isize, Ordering::SeqCst);
}
fn get_dll_module() -> Option<HMODULE> {
let ptr = DLL_MODULE_PTR.load(Ordering::SeqCst);
if ptr == 0 {
None
} else {
Some(HMODULE(ptr as *mut c_void))
}
}
// ─────────────────────────────────────────────────────────────────────────────
// File Association Check
// ─────────────────────────────────────────────────────────────────────────────
/// Check if Readest.exe is the default application for a given file extension.
fn is_readest_default_for_extension(ext: &str) -> bool {
let ext_wide: Vec<u16> = ext.encode_utf16().chain(std::iter::once(0)).collect();
let mut buffer = [0u16; 260];
let mut buffer_size = buffer.len() as u32;
unsafe {
let result = AssocQueryStringW(
ASSOCF_NONE,
ASSOCSTR_EXECUTABLE,
PCWSTR(ext_wide.as_ptr()),
None,
Some(PWSTR(buffer.as_mut_ptr())),
&mut buffer_size,
);
if result.is_ok() {
let len = buffer.iter().position(|&c| c == 0).unwrap_or(buffer.len());
let path = String::from_utf16_lossy(&buffer[..len]).to_lowercase();
return path.contains("readest");
}
}
false
}
/// Check if Readest is the default app for a specific file path.
fn is_readest_default_for_file(path: &PathBuf) -> bool {
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
let ext_with_dot = format!(".{}", ext.to_lowercase());
return is_readest_default_for_extension(&ext_with_dot);
}
false
}
// ─────────────────────────────────────────────────────────────────────────────
// ThumbnailProvider
// ─────────────────────────────────────────────────────────────────────────────
/// Interior mutability wrapper for COM single-threaded apartment
struct ComCell<T>(UnsafeCell<T>);
impl<T> ComCell<T> {
fn new(value: T) -> Self {
Self(UnsafeCell::new(value))
}
fn get(&self) -> &T {
unsafe { &*self.0.get() }
}
fn set(&self, value: T) {
unsafe {
*self.0.get() = value;
}
}
}
// SAFETY: COM thumbnail providers run in single-threaded apartment (STA)
unsafe impl<T> Sync for ComCell<T> {}
unsafe impl<T> Send for ComCell<T> {}
#[implement(IThumbnailProvider, IInitializeWithItem)]
pub struct ThumbnailProvider {
file_path: ComCell<Option<PathBuf>>,
file_ext: ComCell<Option<String>>,
should_provide: ComCell<bool>,
}
impl ThumbnailProvider {
pub fn new() -> Self {
dll_add_ref();
Self {
file_path: ComCell::new(None),
file_ext: ComCell::new(None),
should_provide: ComCell::new(false),
}
}
}
impl Default for ThumbnailProvider {
fn default() -> Self {
Self::new()
}
}
impl Drop for ThumbnailProvider {
fn drop(&mut self) {
dll_release();
}
}
impl IInitializeWithItem_Impl for ThumbnailProvider_Impl {
fn Initialize(&self, psi: Ref<'_, IShellItem>, _grfmode: u32) -> windows::core::Result<()> {
let item = psi.ok()?;
unsafe {
let path_pwstr = item.GetDisplayName(SIGDN_FILESYSPATH)?;
let mut len = 0usize;
let mut ptr = path_pwstr.0;
while *ptr != 0 {
len += 1;
ptr = ptr.add(1);
}
let slice = std::slice::from_raw_parts(path_pwstr.0, len);
let path_str = String::from_utf16_lossy(slice);
let path = PathBuf::from(&path_str);
CoTaskMemFree(Some(path_pwstr.0 as *const c_void));
let is_default = is_readest_default_for_file(&path);
self.should_provide.set(is_default);
if !is_default {
return Ok(());
}
let ext = path
.extension()
.and_then(|e| e.to_str())
.map(|s| s.to_lowercase())
.unwrap_or_default();
self.file_path.set(Some(path));
self.file_ext.set(Some(ext));
}
Ok(())
}
}
impl IThumbnailProvider_Impl for ThumbnailProvider_Impl {
fn GetThumbnail(
&self,
cx: u32,
phbmp: *mut HBITMAP,
pdwalpha: *mut WTS_ALPHATYPE,
) -> windows::core::Result<()> {
if !*self.should_provide.get() {
return Err(E_FAIL.into());
}
let path = self.file_path.get().as_ref().ok_or(E_FAIL)?;
let ext = self.file_ext.get().as_ref().ok_or(E_FAIL)?;
let png_bytes = cached_thumbnail_for_path(path, ext, cx).map_err(|_| E_FAIL)?;
let img = image::load_from_memory(&png_bytes).map_err(|_| E_FAIL)?;
let rgba = img.to_rgba8();
let (width, height) = (rgba.width(), rgba.height());
let bmi = BITMAPINFO {
bmiHeader: BITMAPINFOHEADER {
biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32,
biWidth: width as i32,
biHeight: -(height as i32),
biPlanes: 1,
biBitCount: 32,
biCompression: BI_RGB.0,
..Default::default()
},
..Default::default()
};
let mut bits: *mut c_void = std::ptr::null_mut();
unsafe {
let hbmp = CreateDIBSection(None, &bmi, DIB_RGB_COLORS, &mut bits, None, 0)
.map_err(|_| E_FAIL)?;
if bits.is_null() {
return Err(E_FAIL.into());
}
// RGBA -> BGRA
let dst =
std::slice::from_raw_parts_mut(bits as *mut u8, (width * height * 4) as usize);
let src = rgba.as_raw();
for i in 0..(width * height) as usize {
let si = i * 4;
dst[si] = src[si + 2]; // B
dst[si + 1] = src[si + 1]; // G
dst[si + 2] = src[si]; // R
dst[si + 3] = src[si + 3]; // A
}
*phbmp = hbmp;
*pdwalpha = WTSAT_ARGB;
}
Ok(())
}
}
// ─────────────────────────────────────────────────────────────────────────────
// ClassFactory
// ─────────────────────────────────────────────────────────────────────────────
#[implement(IClassFactory)]
pub struct ThumbnailProviderFactory;
impl ThumbnailProviderFactory {
pub fn new() -> Self {
dll_add_ref();
Self
}
}
impl Default for ThumbnailProviderFactory {
fn default() -> Self {
Self::new()
}
}
impl Drop for ThumbnailProviderFactory {
fn drop(&mut self) {
dll_release();
}
}
impl IClassFactory_Impl for ThumbnailProviderFactory_Impl {
fn CreateInstance(
&self,
punkouter: Ref<'_, IUnknown>,
riid: *const GUID,
ppvobject: *mut *mut c_void,
) -> windows::core::Result<()> {
unsafe {
if ppvobject.is_null() {
return Err(E_INVALIDARG.into());
}
*ppvobject = std::ptr::null_mut();
if !punkouter.is_null() {
return Err(CLASS_E_NOAGGREGATION.into());
}
let provider: IThumbnailProvider = ThumbnailProvider::new().into();
provider.query(&*riid, ppvobject).ok()
}
}
fn LockServer(&self, flock: BOOL) -> windows::core::Result<()> {
if flock.as_bool() {
dll_add_ref();
} else {
dll_release();
}
Ok(())
}
}
// ─────────────────────────────────────────────────────────────────────────────
// DLL Exports
// ─────────────────────────────────────────────────────────────────────────────
#[no_mangle]
pub extern "system" fn DllMain(hinstance: HMODULE, reason: u32, _reserved: *mut c_void) -> BOOL {
const DLL_PROCESS_ATTACH: u32 = 1;
if reason == DLL_PROCESS_ATTACH {
set_dll_module(hinstance);
}
BOOL::from(true)
}
#[no_mangle]
pub extern "system" fn DllCanUnloadNow() -> HRESULT {
if DLL_REF_COUNT.load(Ordering::SeqCst) == 0 {
S_OK
} else {
S_FALSE
}
}
#[no_mangle]
pub unsafe extern "system" fn DllGetClassObject(
rclsid: *const GUID,
riid: *const GUID,
ppv: *mut *mut c_void,
) -> HRESULT {
if ppv.is_null() || rclsid.is_null() || riid.is_null() {
return E_INVALIDARG;
}
*ppv = std::ptr::null_mut();
if *rclsid != CLSID_READEST_THUMBNAIL {
return E_NOINTERFACE;
}
if *riid != IClassFactory::IID && *riid != IUnknown::IID {
return E_NOINTERFACE;
}
let factory: IClassFactory = ThumbnailProviderFactory::new().into();
factory.query(&*riid, ppv)
}
#[no_mangle]
pub unsafe extern "system" fn DllRegisterServer() -> HRESULT {
match register_server_impl() {
Ok(()) => S_OK,
Err(e) => e,
}
}
#[no_mangle]
pub unsafe extern "system" fn DllUnregisterServer() -> HRESULT {
let _ = unregister_server_impl();
S_OK
}
// ─────────────────────────────────────────────────────────────────────────────
// Registry helpers
// ─────────────────────────────────────────────────────────────────────────────
fn get_dll_path() -> Option<String> {
let module = get_dll_module()?;
let mut buffer = [0u16; 260];
unsafe {
let len = GetModuleFileNameW(Some(module), &mut buffer);
if len == 0 {
None
} else {
Some(String::from_utf16_lossy(&buffer[..len as usize]))
}
}
}
fn clsid_string() -> String {
format!(
"{{{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}}}",
CLSID_READEST_THUMBNAIL.data1,
CLSID_READEST_THUMBNAIL.data2,
CLSID_READEST_THUMBNAIL.data3,
CLSID_READEST_THUMBNAIL.data4[0],
CLSID_READEST_THUMBNAIL.data4[1],
CLSID_READEST_THUMBNAIL.data4[2],
CLSID_READEST_THUMBNAIL.data4[3],
CLSID_READEST_THUMBNAIL.data4[4],
CLSID_READEST_THUMBNAIL.data4[5],
CLSID_READEST_THUMBNAIL.data4[6],
CLSID_READEST_THUMBNAIL.data4[7]
)
}
fn to_wide(s: &str) -> Vec<u16> {
s.encode_utf16().chain(std::iter::once(0)).collect()
}
unsafe fn set_reg_value(key: HKEY, name: &str, value: &str) -> Result<(), HRESULT> {
let name_w = to_wide(name);
let value_w = to_wide(value);
let bytes: &[u8] = std::slice::from_raw_parts(value_w.as_ptr() as *const u8, value_w.len() * 2);
if RegSetValueExW(key, PCWSTR(name_w.as_ptr()), Some(0), REG_SZ, Some(bytes)).is_err() {
Err(E_FAIL)
} else {
Ok(())
}
}
unsafe fn create_reg_key(parent: HKEY, subkey: &str) -> Result<HKEY, HRESULT> {
let subkey_w = to_wide(subkey);
let mut hkey = HKEY::default();
let result = RegCreateKeyExW(
parent,
PCWSTR(subkey_w.as_ptr()),
Some(0),
None,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
None,
&mut hkey,
None,
);
if result.is_err() {
Err(E_FAIL)
} else {
Ok(hkey)
}
}
unsafe fn register_server_impl() -> Result<(), HRESULT> {
let dll_path = get_dll_path().ok_or(E_FAIL)?;
let clsid = clsid_string();
// CLSID key
let clsid_key = create_reg_key(HKEY_CLASSES_ROOT, &format!("CLSID\\{}", clsid))?;
set_reg_value(clsid_key, "", "Readest Thumbnail Provider")?;
// CRITICAL: DisableProcessIsolation = 1
let disable_isolation_name = to_wide("DisableProcessIsolation");
let value: u32 = 1;
let _ = windows::Win32::System::Registry::RegSetValueExW(
clsid_key,
PCWSTR(disable_isolation_name.as_ptr()),
Some(0),
windows::Win32::System::Registry::REG_DWORD,
Some(std::slice::from_raw_parts(
&value as *const u32 as *const u8,
4,
)),
);
let inproc_key = create_reg_key(clsid_key, "InprocServer32")?;
set_reg_value(inproc_key, "", &dll_path)?;
set_reg_value(inproc_key, "ThreadingModel", "Apartment")?;
let _ = RegCloseKey(inproc_key);
let _ = RegCloseKey(clsid_key);
// Register ShellEx thumbnail handler for each extension
for ext in SUPPORTED_EXTENSIONS {
let ext_shellex_path =
format!("{}\\ShellEx\\{{e357fccd-a995-4576-b01f-234630154e96}}", ext);
if let Ok(ext_shellex_key) = create_reg_key(HKEY_CLASSES_ROOT, &ext_shellex_path) {
let _ = set_reg_value(ext_shellex_key, "", &clsid);
let _ = RegCloseKey(ext_shellex_key);
}
}
Ok(())
}
unsafe fn unregister_server_impl() -> Result<(), HRESULT> {
let clsid = clsid_string();
let clsid_path = to_wide(&format!("CLSID\\{}", clsid));
let _ = RegDeleteTreeW(HKEY_CLASSES_ROOT, PCWSTR(clsid_path.as_ptr()));
for ext in SUPPORTED_EXTENSIONS {
let ext_path = to_wide(&format!(
"{}\\ShellEx\\{{e357fccd-a995-4576-b01f-234630154e96}}",
ext
));
let _ = RegDeleteTreeW(HKEY_CLASSES_ROOT, PCWSTR(ext_path.as_ptr()));
}
Ok(())
}
@@ -0,0 +1,648 @@
/// Cover image extraction for various eBook formats
///
/// Supports: EPUB, MOBI/AZW3/KF8, FB2, CBZ/CBR, TXT
use anyhow::{anyhow, Result};
use base64::engine::general_purpose;
use base64::Engine as _;
use directories_next::ProjectDirs;
use image::{imageops, DynamicImage, Rgba};
use md5::Context;
use once_cell::sync::Lazy;
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::path::Path;
use zip::ZipArchive;
/// Thumbnail cache directory (per-user)
static CACHE_DIR: Lazy<Option<std::path::PathBuf>> = Lazy::new(|| {
ProjectDirs::from("app", "Readest", "").map(|pd| {
let dir = pd.cache_dir().join("thumbnails");
let _ = std::fs::create_dir_all(&dir);
dir
})
});
// ─────────────────────────────────────────────────────────────────────────────
// EPUB extraction
// ─────────────────────────────────────────────────────────────────────────────
/// Extract cover image bytes from an EPUB file.
pub fn extract_epub_cover_bytes<R: Read + Seek>(reader: R) -> Result<Vec<u8>> {
let mut archive = ZipArchive::new(reader)?;
// Pass 1: Look for files with "cover" in the name
let mut candidates: Vec<(usize, String, u64)> = Vec::new();
for i in 0..archive.len() {
let file = archive.by_index(i)?;
let name = file.name().to_lowercase();
let size = file.size();
drop(file);
if is_image_extension(&name) && (name.contains("cover") || name.contains("front")) {
candidates.push((i, name, size));
}
}
// Sort by priority: exact "cover" match first, then by size
if !candidates.is_empty() {
candidates.sort_by(|a, b| {
let a_exact = a.1.contains("cover.") || a.1.ends_with("cover");
let b_exact = b.1.contains("cover.") || b.1.ends_with("cover");
match (a_exact, b_exact) {
(true, false) => std::cmp::Ordering::Less,
(false, true) => std::cmp::Ordering::Greater,
_ => b.2.cmp(&a.2),
}
});
let idx = candidates[0].0;
let mut file = archive.by_index(idx)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
return Ok(buf);
}
// Pass 2: Parse container.xml to find OPF, then parse OPF for cover
let container_xml = read_zip_file_to_string(&mut archive, "META-INF/container.xml");
if let Ok(xml) = container_xml {
if let Some(rootfile) = extract_attribute(&xml, "rootfile", "full-path") {
let opf_content = read_zip_file_to_string(&mut archive, &rootfile);
if let Ok(opf) = opf_content {
if let Some(cover_id) = find_cover_id_in_opf(&opf) {
if let Some(href) = find_href_by_id_in_opf(&opf, &cover_id) {
let base = Path::new(&rootfile).parent().unwrap_or(Path::new(""));
let cover_path = base.join(&href).to_string_lossy().replace('\\', "/");
if let Ok(bytes) = read_zip_file_to_bytes(&mut archive, &cover_path) {
return Ok(bytes);
}
}
}
if let Some(href) = find_first_image_in_manifest(&opf) {
let base = Path::new(&rootfile).parent().unwrap_or(Path::new(""));
let cover_path = base.join(&href).to_string_lossy().replace('\\', "/");
if let Ok(bytes) = read_zip_file_to_bytes(&mut archive, &cover_path) {
return Ok(bytes);
}
}
}
}
}
// Pass 3: Just grab the largest image file
let mut largest: Option<(usize, u64)> = None;
for i in 0..archive.len() {
let file = archive.by_index(i)?;
let name = file.name().to_lowercase();
let size = file.size();
drop(file);
if is_image_extension(&name) && (largest.is_none() || size > largest.unwrap().1) {
largest = Some((i, size));
}
}
if let Some((idx, _)) = largest {
let mut file = archive.by_index(idx)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
return Ok(buf);
}
Err(anyhow!("No cover image found in EPUB"))
}
// ─────────────────────────────────────────────────────────────────────────────
// MOBI/AZW3/KF8 extraction
// ─────────────────────────────────────────────────────────────────────────────
/// Extract cover image from MOBI/AZW3/KF8 files.
pub fn extract_mobi_cover_bytes<R: Read + Seek>(mut reader: R) -> Result<Vec<u8>> {
let mut header = [0u8; 78];
reader.read_exact(&mut header)?;
if &header[60..68] != b"BOOKMOBI" {
return Err(anyhow!("Not a valid MOBI file"));
}
let num_records = u16::from_be_bytes([header[76], header[77]]) as usize;
let mut record_offsets: Vec<u32> = Vec::with_capacity(num_records);
for _ in 0..num_records {
let mut rec = [0u8; 8];
reader.read_exact(&mut rec)?;
record_offsets.push(u32::from_be_bytes([rec[0], rec[1], rec[2], rec[3]]));
}
if record_offsets.is_empty() {
return Err(anyhow!("No records in MOBI file"));
}
reader.seek(SeekFrom::Start(record_offsets[0] as u64))?;
let mut mobi_header = [0u8; 256];
reader.read_exact(&mut mobi_header)?;
if &mobi_header[16..20] != b"MOBI" {
return Err(anyhow!("Invalid MOBI header"));
}
let header_length = u32::from_be_bytes([
mobi_header[20],
mobi_header[21],
mobi_header[22],
mobi_header[23],
]) as usize;
let exth_flags = u32::from_be_bytes([
mobi_header[128],
mobi_header[129],
mobi_header[130],
mobi_header[131],
]);
if exth_flags & 0x40 == 0 {
return Err(anyhow!("No EXTH header in MOBI file"));
}
let exth_offset = record_offsets[0] as u64 + 16 + header_length as u64;
reader.seek(SeekFrom::Start(exth_offset))?;
let mut exth_magic = [0u8; 4];
reader.read_exact(&mut exth_magic)?;
if &exth_magic != b"EXTH" {
return Err(anyhow!("EXTH header not found"));
}
let mut exth_len_bytes = [0u8; 4];
reader.read_exact(&mut exth_len_bytes)?;
let mut exth_count_bytes = [0u8; 4];
reader.read_exact(&mut exth_count_bytes)?;
let exth_count = u32::from_be_bytes(exth_count_bytes) as usize;
let mut cover_offset: Option<u32> = None;
let first_img_idx = u32::from_be_bytes([
mobi_header[108],
mobi_header[109],
mobi_header[110],
mobi_header[111],
]);
for _ in 0..exth_count {
let mut rec_header = [0u8; 8];
if reader.read_exact(&mut rec_header).is_err() {
break;
}
let rec_type =
u32::from_be_bytes([rec_header[0], rec_header[1], rec_header[2], rec_header[3]]);
let rec_len =
u32::from_be_bytes([rec_header[4], rec_header[5], rec_header[6], rec_header[7]])
as usize;
let data_len = rec_len.saturating_sub(8);
let mut data = vec![0u8; data_len];
if reader.read_exact(&mut data).is_err() {
break;
}
if rec_type == 201 && data_len >= 4 {
cover_offset = Some(u32::from_be_bytes([data[0], data[1], data[2], data[3]]));
}
}
let cover_record_idx = if let Some(offset) = cover_offset {
first_img_idx + offset
} else {
first_img_idx
};
if cover_record_idx as usize >= record_offsets.len() {
return Err(anyhow!("Cover record index out of bounds"));
}
let start = record_offsets[cover_record_idx as usize] as u64;
let end = if (cover_record_idx as usize + 1) < record_offsets.len() {
record_offsets[cover_record_idx as usize + 1] as u64
} else {
reader.seek(SeekFrom::End(0))?;
reader.stream_position()?
};
let len = (end - start) as usize;
reader.seek(SeekFrom::Start(start))?;
let mut cover_data = vec![0u8; len];
reader.read_exact(&mut cover_data)?;
if cover_data.starts_with(&[0xFF, 0xD8, 0xFF])
|| cover_data.starts_with(&[0x89, 0x50, 0x4E, 0x47])
|| cover_data.starts_with(b"GIF")
{
return Ok(cover_data);
}
Err(anyhow!("No valid cover image found in MOBI"))
}
// ─────────────────────────────────────────────────────────────────────────────
// CBZ extraction
// ─────────────────────────────────────────────────────────────────────────────
/// Extract cover image from CBZ (comic book ZIP) file.
pub fn extract_cbz_cover_bytes<R: Read + Seek>(reader: R) -> Result<Vec<u8>> {
let mut archive = ZipArchive::new(reader)?;
let mut images: Vec<(usize, String)> = Vec::new();
for i in 0..archive.len() {
let file = archive.by_index(i)?;
let name = file.name().to_string();
drop(file);
if is_image_extension(&name.to_lowercase()) {
images.push((i, name));
}
}
images.sort_by(|a, b| a.1.cmp(&b.1));
if let Some((idx, _)) = images.first() {
let mut file = archive.by_index(*idx)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
return Ok(buf);
}
Err(anyhow!("No images found in CBZ"))
}
// ─────────────────────────────────────────────────────────────────────────────
// FB2 extraction
// ─────────────────────────────────────────────────────────────────────────────
/// Extract cover image from FB2 (FictionBook) file.
pub fn extract_fb2_cover_bytes<R: Read>(mut reader: R) -> Result<Vec<u8>> {
let mut content = String::new();
reader.read_to_string(&mut content)?;
let cover_id = if let Some(start) = content.find("<coverpage>") {
let end = content[start..].find("</coverpage>").unwrap_or(500);
let coverpage = &content[start..start + end];
if let Some(href_pos) = coverpage.find("href=\"#") {
let id_start = href_pos + 7;
let id_end = coverpage[id_start..].find('"').unwrap_or(50);
Some(coverpage[id_start..id_start + id_end].to_string())
} else if let Some(href_pos) = coverpage.find("l:href=\"#") {
let id_start = href_pos + 9;
let id_end = coverpage[id_start..].find('"').unwrap_or(50);
Some(coverpage[id_start..id_start + id_end].to_string())
} else {
None
}
} else {
None
};
let search_pattern = if let Some(ref id) = cover_id {
format!("<binary id=\"{}\"", id)
} else {
"<binary".to_string()
};
if let Some(pos) = content.find(&search_pattern) {
if let Some(tag_end) = content[pos..].find('>') {
let data_start = pos + tag_end + 1;
if let Some(data_end) = content[data_start..].find("</binary>") {
let b64_data = content[data_start..data_start + data_end].trim();
let b64_clean: String = b64_data.chars().filter(|c| !c.is_whitespace()).collect();
let bytes = general_purpose::STANDARD.decode(&b64_clean)?;
return Ok(bytes);
}
}
}
if cover_id.is_some() {
if let Some(pos) = content.find("<binary") {
if let Some(tag_end) = content[pos..].find('>') {
let data_start = pos + tag_end + 1;
if let Some(data_end) = content[data_start..].find("</binary>") {
let b64_data = content[data_start..data_start + data_end].trim();
let b64_clean: String =
b64_data.chars().filter(|c| !c.is_whitespace()).collect();
let bytes = general_purpose::STANDARD.decode(&b64_clean)?;
return Ok(bytes);
}
}
}
}
Err(anyhow!("No cover image found in FB2"))
}
// ─────────────────────────────────────────────────────────────────────────────
// TXT "cover" (placeholder)
// ─────────────────────────────────────────────────────────────────────────────
/// Generate a placeholder thumbnail for TXT files.
pub fn extract_txt_cover_bytes<R: Read>(mut reader: R, size: u32) -> Result<Vec<u8>> {
let mut buf = vec![0u8; 4096];
let _n = reader.read(&mut buf)?;
let mut img = image::RgbaImage::from_pixel(size, size, Rgba([245, 245, 245, 255]));
for x in 0..size {
img.put_pixel(x, 0, Rgba([200, 200, 200, 255]));
img.put_pixel(x, size - 1, Rgba([200, 200, 200, 255]));
}
for y in 0..size {
img.put_pixel(0, y, Rgba([200, 200, 200, 255]));
img.put_pixel(size - 1, y, Rgba([200, 200, 200, 255]));
}
let mut out = Vec::new();
DynamicImage::ImageRgba8(img).write_to(&mut Cursor::new(&mut out), image::ImageFormat::Png)?;
Ok(out)
}
// ─────────────────────────────────────────────────────────────────────────────
// Unified extraction by extension
// ─────────────────────────────────────────────────────────────────────────────
/// Extract cover image bytes based on file extension.
pub fn extract_cover_bytes_by_ext(path: &Path, ext: &str) -> Result<Vec<u8>> {
let file = std::fs::File::open(path)?;
match ext.to_lowercase().as_str() {
"epub" => extract_epub_cover_bytes(file),
"mobi" | "azw" | "azw3" | "kf8" | "prc" => extract_mobi_cover_bytes(file),
"cbz" | "cbr" => extract_cbz_cover_bytes(file),
"fb2" => extract_fb2_cover_bytes(file),
"txt" => extract_txt_cover_bytes(file, 256),
_ => Err(anyhow!("Unsupported format: {}", ext)),
}
}
// ─────────────────────────────────────────────────────────────────────────────
// Thumbnail creation with overlay
// ─────────────────────────────────────────────────────────────────────────────
/// Create a thumbnail from cover image bytes with Readest icon overlay.
pub fn create_thumbnail_with_overlay(cover_bytes: &[u8], requested_size: u32) -> Result<Vec<u8>> {
let img = image::load_from_memory(cover_bytes)?;
let thumbnail = img.thumbnail(requested_size, requested_size);
let overlay_img = load_overlay_icon();
let mut base = thumbnail.to_rgba8();
let (base_w, base_h) = (base.width(), base.height());
if let Some(ov) = overlay_img {
let overlay_size = (requested_size / 5).clamp(24, 48);
let ov_resized = ov.resize(overlay_size, overlay_size, imageops::FilterType::Lanczos3);
let ovb = ov_resized.to_rgba8();
let (ov_w, ov_h) = (ovb.width(), ovb.height());
let x = base_w.saturating_sub(ov_w + 4);
let y = base_h.saturating_sub(ov_h + 4);
for oy in 0..ov_h {
for ox in 0..ov_w {
let dst_x = x + ox;
let dst_y = y + oy;
if dst_x < base_w && dst_y < base_h {
let src_pixel = ovb.get_pixel(ox, oy);
let alpha = src_pixel.0[3] as f32 / 255.0;
if alpha > 0.0 {
let dst_pixel = base.get_pixel(dst_x, dst_y);
let mut result = dst_pixel.0;
for c in 0..3 {
let fg = src_pixel.0[c] as f32;
let bg = result[c] as f32;
result[c] = (fg * alpha + bg * (1.0 - alpha)) as u8;
}
result[3] = 255;
base.put_pixel(dst_x, dst_y, Rgba(result));
}
}
}
}
}
let mut out = Vec::new();
DynamicImage::ImageRgba8(base).write_to(&mut Cursor::new(&mut out), image::ImageFormat::Png)?;
Ok(out)
}
/// Load the Readest overlay icon.
fn load_overlay_icon() -> Option<DynamicImage> {
// Try embedded icon
let icon_bytes = include_bytes!("../../../public/icon.png");
if let Ok(img) = image::load_from_memory(icon_bytes) {
return Some(img);
}
// Fallback: try loading from filesystem
if let Ok(exe) = std::env::current_exe() {
let candidates = [
exe.parent().map(|p| p.join("icon.png")),
exe.parent().map(|p| p.join("resources").join("icon.png")),
exe.parent()
.and_then(|p| p.parent())
.map(|p| p.join("resources").join("icon.png")),
];
for candidate in candidates.into_iter().flatten() {
if candidate.exists() {
if let Ok(bytes) = std::fs::read(&candidate) {
if let Ok(img) = image::load_from_memory(&bytes) {
return Some(img);
}
}
}
}
}
None
}
// ─────────────────────────────────────────────────────────────────────────────
// Caching
// ─────────────────────────────────────────────────────────────────────────────
/// Generate a thumbnail with disk caching.
pub fn cached_thumbnail_for_path(path: &Path, ext: &str, size: u32) -> Result<Vec<u8>> {
// Compute cache key by hashing file parts for stability without loading entire file
let mut hasher = Context::new();
hasher.consume(ext.as_bytes());
hasher.consume(&size.to_le_bytes());
let file = std::fs::File::open(path)?;
let metadata = file.metadata()?;
let file_len = metadata.len();
// Read partial chunks like the TypeScript partialMD5 implementation
const STEP: u64 = 1024;
const SIZE: u64 = 1024;
let mut file = file;
for i in -1i32..=10 {
let pos = if i == -1 {
256u64
} else {
STEP << (2 * i as u32)
};
let start = pos.min(file_len);
let end = (start + SIZE).min(file_len);
if start >= file_len {
break;
}
file.seek(SeekFrom::Start(start))?;
let mut buf = vec![0u8; (end - start) as usize];
file.read_exact(&mut buf)?;
hasher.consume(&buf);
}
let digest = hasher.finalize();
let key = format!("{:x}.png", digest);
if let Some(ref dir) = *CACHE_DIR {
let cache_path = dir.join(&key);
if cache_path.exists() {
if let Ok(cached) = std::fs::read(&cache_path) {
return Ok(cached);
}
}
}
let cover = extract_cover_bytes_by_ext(path, ext)?;
let thumbnail = create_thumbnail_with_overlay(&cover, size)?;
if let Some(ref dir) = *CACHE_DIR {
let cache_path = dir.join(&key);
let _ = std::fs::write(&cache_path, &thumbnail);
}
Ok(thumbnail)
}
// ─────────────────────────────────────────────────────────────────────────────
// Helper functions
// ─────────────────────────────────────────────────────────────────────────────
fn is_image_extension(name: &str) -> bool {
name.ends_with(".jpg")
|| name.ends_with(".jpeg")
|| name.ends_with(".png")
|| name.ends_with(".gif")
|| name.ends_with(".webp")
|| name.ends_with(".bmp")
}
fn read_zip_file_to_string<R: Read + Seek>(
archive: &mut ZipArchive<R>,
name: &str,
) -> Result<String> {
let mut file = archive.by_name(name)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
fn read_zip_file_to_bytes<R: Read + Seek>(
archive: &mut ZipArchive<R>,
name: &str,
) -> Result<Vec<u8>> {
let mut file = archive.by_name(name)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
Ok(buf)
}
fn extract_attribute(xml: &str, tag: &str, attr: &str) -> Option<String> {
let pattern = format!("<{}", tag);
if let Some(tag_pos) = xml.find(&pattern) {
let tag_end = xml[tag_pos..].find('>').unwrap_or(500) + tag_pos;
let tag_content = &xml[tag_pos..tag_end];
let attr_pattern = format!("{}=\"", attr);
if let Some(attr_pos) = tag_content.find(&attr_pattern) {
let value_start = attr_pos + attr_pattern.len();
if let Some(value_end) = tag_content[value_start..].find('"') {
return Some(tag_content[value_start..value_start + value_end].to_string());
}
}
}
None
}
fn find_cover_id_in_opf(opf: &str) -> Option<String> {
if let Some(pos) = opf.find("name=\"cover\"") {
let window_start = pos.saturating_sub(50);
let window_end = (pos + 100).min(opf.len());
let window = &opf[window_start..window_end];
if let Some(content_pos) = window.find("content=\"") {
let start = content_pos + 9;
if let Some(end) = window[start..].find('"') {
return Some(window[start..start + end].to_string());
}
}
}
if let Some(pos) = opf.find("properties=\"cover-image\"") {
let window_start = pos.saturating_sub(200);
let window_end = pos;
let window = &opf[window_start..window_end];
if let Some(id_pos) = window.rfind("id=\"") {
let start = id_pos + 4;
if let Some(end) = window[start..].find('"') {
return Some(window[start..start + end].to_string());
}
}
}
None
}
fn find_href_by_id_in_opf(opf: &str, id: &str) -> Option<String> {
let pattern = format!("id=\"{}\"", id);
if let Some(pos) = opf.find(&pattern) {
let window_start = pos.saturating_sub(10);
let window_end = (pos + 200).min(opf.len());
let window = &opf[window_start..window_end];
if let Some(href_pos) = window.find("href=\"") {
let start = href_pos + 6;
if let Some(end) = window[start..].find('"') {
return Some(window[start..start + end].to_string());
}
}
}
None
}
fn find_first_image_in_manifest(opf: &str) -> Option<String> {
let manifest_start = opf.find("<manifest")?;
let manifest_end = opf[manifest_start..]
.find("</manifest>")
.map(|e| manifest_start + e)?;
let manifest = &opf[manifest_start..manifest_end];
for media_type in ["image/jpeg", "image/png", "image/gif", "image/webp"] {
let pattern = format!("media-type=\"{}\"", media_type);
if let Some(pos) = manifest.find(&pattern) {
let window_start = pos.saturating_sub(200);
let window = &manifest[window_start..pos];
if let Some(href_pos) = window.rfind("href=\"") {
let start = href_pos + 6;
if let Some(end) = window[start..].find('"') {
return Some(window[start..start + end].to_string());
}
}
}
}
None
}
@@ -0,0 +1,13 @@
//! Windows Thumbnail Provider for Readest
//!
//! This module provides Windows Explorer thumbnail support for eBook files.
//! Thumbnails are only shown when Readest is set as the default application.
//!
//! Supported formats: EPUB, MOBI, AZW, AZW3, KF8, FB2, CBZ, CBR
#![allow(non_snake_case)]
mod com_provider;
mod extraction;
pub use extraction::*;
@@ -0,0 +1,65 @@
const options = {
debug: false,
sort: false,
func: {
list: ['_'],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
lngs: [
'de',
'ja',
'es',
'fa',
'fr',
'it',
'el',
'ko',
'uk',
'nl',
'sl',
'sv',
'pl',
'pt',
'ru',
'tr',
'hi',
'id',
'vi',
'ms',
'he',
'ar',
'th',
'bo',
'bn',
'ta',
'si',
'zh-CN',
'zh-TW',
'ro',
'hu',
],
ns: ['translation'],
defaultNs: 'translation',
defaultValue: '__STRING_NOT_TRANSLATED__',
resource: {
loadPath: './public/locales/{{lng}}/{{ns}}.json',
savePath: './public/locales/{{lng}}/{{ns}}.json',
jsonIndent: 2,
lineEnding: '\n',
},
keySeparator: false,
nsSeparator: false,
interpolation: {
prefix: '{{',
suffix: '}}',
},
metadata: {},
allowDynamicKeys: true,
removeUnusedKeys: true,
};
module.exports = {
input: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.test.{js,jsx,ts,tsx}'],
output: '.',
options,
};
@@ -1,52 +0,0 @@
module.exports = {
input: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.test.{js,jsx,ts,tsx}'],
output: '.',
options: {
debug: false,
sort: false,
func: {
list: ['_'],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
lngs: [
'de',
'ja',
'es',
'fr',
'it',
'el',
'ko',
'uk',
'nl',
'pl',
'pt',
'ru',
'tr',
'hi',
'id',
'vi',
'ar',
'th',
'zh-CN',
'zh-TW',
],
ns: ['translation'],
defaultNs: 'translation',
defaultValue: '__STRING_NOT_TRANSLATED__',
resource: {
loadPath: './public/locales/{{lng}}/{{ns}}.json',
savePath: './public/locales/{{lng}}/{{ns}}.json',
jsonIndent: 2,
lineEnding: '\n',
},
keySeparator: false,
nsSeparator: false,
interpolation: {
prefix: '{{',
suffix: '}}',
},
metadata: {},
allowDynamicKeys: true,
removeUnusedKeys: true,
},
};
+74 -16
View File
@@ -1,10 +1,11 @@
import withPWAInit from '@ducanh2912/next-pwa';
import { initOpenNextCloudflareForDev } from '@opennextjs/cloudflare';
import withSerwistInit from '@serwist/next';
import withBundleAnalyzer from '@next/bundle-analyzer';
const isDev = process.env['NODE_ENV'] === 'development';
const appPlatform = process.env['NEXT_PUBLIC_APP_PLATFORM'];
if (isDev) {
const { initOpenNextCloudflareForDev } = await import('@opennextjs/cloudflare');
initOpenNextCloudflareForDev();
}
@@ -25,6 +26,49 @@ const nextConfig = {
// Configure assetPrefix or else the server won't properly resolve your assets.
assetPrefix: '',
reactStrictMode: true,
serverExternalPackages: ['isows'],
webpack: (config) => {
config.resolve.alias = {
...config.resolve.alias,
nunjucks: 'nunjucks/browser/nunjucks.js',
...(appPlatform !== 'web' ? { '@tursodatabase/database-wasm': false } : {}),
};
return config;
},
turbopack: {
resolveAlias: {
nunjucks: 'nunjucks/browser/nunjucks.js',
...(appPlatform !== 'web' ? { '@tursodatabase/database-wasm': './src/utils/stub.ts' } : {}),
},
},
transpilePackages: [
'ai',
'ai-sdk-ollama',
'@ai-sdk/react',
'@assistant-ui/react',
'@assistant-ui/react-ai-sdk',
'@assistant-ui/react-markdown',
'streamdown',
...(isDev
? []
: [
'i18next-browser-languagedetector',
'react-i18next',
'i18next',
'@tauri-apps',
'highlight.js',
'foliate-js',
'marked',
]),
],
async rewrites() {
return [
{
source: '/reader/:ids',
destination: '/reader?ids=:ids',
},
];
},
async headers() {
return [
{
@@ -36,23 +80,37 @@ const nextConfig = {
},
],
},
{
source: '/_next/static/:path*',
headers: [
{
key: 'Cache-Control',
value: isDev
? 'public, max-age=0, must-revalidate'
: 'public, max-age=31536000, immutable',
},
],
},
];
},
};
const withPWA = withPWAInit({
dest: 'public',
disable: isDev || appPlatform !== 'web',
cacheOnFrontEndNav: true,
aggressiveFrontEndNavCaching: true,
reloadOnOnline: true,
swcMinify: true,
fallbacks: {
document: '/offline',
},
workboxOptions: {
disableDevLogs: true,
},
const pwaDisabled = isDev || appPlatform !== 'web';
const withPWA = pwaDisabled
? (config) => config
: withSerwistInit({
swSrc: 'src/sw.ts',
swDest: 'public/sw.js',
cacheOnNavigation: true,
reloadOnOnline: true,
disable: false,
register: true,
scope: '/',
});
const withAnalyzer = withBundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});
export default withPWA(nextConfig);
export default withPWA(withAnalyzer(nextConfig));
+159 -43
View File
@@ -1,7 +1,8 @@
{
"name": "@readest/readest-app",
"version": "0.9.63",
"version": "0.10.4",
"private": true,
"type": "module",
"scripts": {
"dev": "dotenv -e .env.tauri -- next dev",
"build": "dotenv -e .env.tauri -- next build",
@@ -9,17 +10,39 @@
"dev-web": "dotenv -e .env.web -- next dev",
"build-web": "dotenv -e .env.web -- next build",
"start-web": "dotenv -e .env.web -- next start",
"i18n:extract": "i18next-scanner",
"lint": "next lint",
"dev-web:vinext": "dotenv -e .env.web -- vinext dev",
"build-web:vinext": "dotenv -e .env.web -- vinext build",
"start-web:vinext": "dotenv -e .env.web -- vinext start",
"build-tauri": "dotenv -e .env.tauri -- next build",
"i18n:extract": "i18next-scanner --config i18next-scanner.config.cjs",
"lint": "tsgo --noEmit && biome check .",
"test": "dotenv -e .env -e .env.test.local vitest",
"test:coverage": "dotenv -e .env -e .env.test.local -- vitest run --coverage",
"test:browser": "vitest --config vitest.browser.config.mts --watch=false",
"test:tauri": "bash scripts/test-tauri.sh",
"test:pr:web": "pnpm test -- --watch=false && pnpm test:browser",
"test:pr:tauri": "bash scripts/test-tauri.sh",
"test:all": "pnpm test -- --watch=false && pnpm test:browser && bash scripts/test-tauri.sh",
"test:e2e": "wdio run wdio.conf.ts",
"tauri:dev:test": "dotenv -e .env.tauri -- tauri dev --features webdriver",
"tauri:build:test": "dotenv -e .env.tauri -- tauri build --debug --features webdriver",
"tauri": "tauri",
"prepare-public-vendor": "mkdirp ./public/vendor/pdfjs",
"copy-pdfjs-js": "cpx \"../../packages/foliate-js/node_modules/pdfjs-dist/legacy/build/{pdf.worker.min.mjs,pdf.mjs,pdf.d.mts}\" ./public/vendor/pdfjs",
"fmt:check": "cargo fmt -p Readest --check",
"clippy:check": "cargo clippy -p Readest --no-deps -- -D warnings",
"format": "pnpm -w format",
"format:check": "pnpm -w format:check",
"prepare-public-vendor": "mkdirp ./public/vendor/pdfjs ./public/vendor/simplecc",
"copy-pdfjs-js": "cpx \"../../packages/foliate-js/node_modules/pdfjs-dist/legacy/build/{pdf.worker.min.mjs,pdf.min.mjs,pdf.d.mts}\" ./public/vendor/pdfjs",
"copy-pdfjs-wasm": "cpx \"../../packages/foliate-js/node_modules/pdfjs-dist/wasm/{openjpeg.wasm,qcms_bg.wasm}\" ./public/vendor/pdfjs",
"copy-pdfjs-fonts": "cpx \"../../packages/foliate-js/node_modules/pdfjs-dist/{cmaps,standard_fonts}/*\" ./public/vendor/pdfjs",
"copy-flatten-pdfjs-annotation-layer-css": "npx postcss \"../../packages/foliate-js/vendor/pdfjs/annotation_layer_builder.css\" --no-map -u postcss-nested > ./public/vendor/pdfjs/annotation_layer_builder.css",
"copy-flatten-pdfjs-text-layer-css": "npx postcss \"../../packages/foliate-js/vendor/pdfjs/text_layer_builder.css\" --no-map -u postcss-nested > ./public/vendor/pdfjs/text_layer_builder.css",
"copy-flatten-pdfjs-css": "pnpm copy-flatten-pdfjs-annotation-layer-css && pnpm copy-flatten-pdfjs-text-layer-css",
"copy-pdfjs": "pnpm copy-pdfjs-js && pnpm copy-pdfjs-fonts && pnpm copy-flatten-pdfjs-css",
"copy-pdfjs": "pnpm copy-pdfjs-js && pnpm copy-pdfjs-wasm && pnpm copy-pdfjs-fonts && pnpm copy-flatten-pdfjs-css",
"copy-simplecc": "cpx \"../../packages/simplecc-wasm/dist/web/*\" ./public/vendor/simplecc",
"setup-pdfjs": "pnpm prepare-public-vendor && pnpm copy-pdfjs",
"setup-simplecc": "pnpm prepare-public-vendor && pnpm copy-simplecc",
"setup-vendors": "pnpm setup-pdfjs && pnpm setup-simplecc",
"build-win-x64": "dotenv -e .env.tauri.local -- tauri build --target i686-pc-windows-msvc --bundles nsis",
"build-win-arm64": "dotenv -e .env.tauri.local -- tauri build --target aarch64-pc-windows-msvc --bundles nsis",
"build-linux-x64": "dotenv -e .env.tauri.local -- tauri build --target x86_64-unknown-linux-gnu --bundles appimage",
@@ -32,92 +55,185 @@
"release-ios-appstore": "dotenv -e .env.ios-appstore.local -- bash scripts/release-ios-appstore.sh",
"release-google-play": "dotenv -e .env.google-play.local -- bash scripts/release-google-play.sh",
"config-wrangler": "sed -i \"s/\\${TRANSLATIONS_KV_ID}/$TRANSLATIONS_KV_ID/g\" wrangler.toml",
"preview": "NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"upload": "NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare build && opennextjs-cloudflare upload",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
"preview": "pnpm patch-build-webpack && NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare build && pnpm restore-build-original && opennextjs-cloudflare preview --ip 0.0.0.0 --port 3001",
"deploy": "pnpm patch-build-webpack && NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare build && pnpm restore-build-original && opennextjs-cloudflare deploy",
"upload": "pnpm patch-build-webpack && NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare build && pnpm restore-build-original && opennextjs-cloudflare upload",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts",
"patch-build-webpack": "if [ \"$(uname)\" = \"Darwin\" ]; then sed -i '' 's/next build\"/next build --webpack\"/' package.json; else sed -i 's/next build\"/next build --webpack\"/' package.json; fi",
"restore-build-original": "if [ \"$(uname)\" = \"Darwin\" ]; then sed -i '' 's/next build --webpack\"/next build\"/' package.json; else sed -i 's/next build --webpack\"/next build\"/' package.json; fi",
"update-metadata": "bash ./scripts/sync-release-notes.sh release-notes.json ../../data/metainfo/appdata.xml",
"check:optional-chaining": "count=$(grep -rno '\\?\\.[a-zA-Z_$]' .next/static/chunks/* out/_next/static/chunks/* | wc -l); if [ \"$count\" -gt 0 ]; then echo '❌ Optional chaining found in output!'; exit 1; else echo '✅ No optional chaining found.'; fi",
"check:translations": "count=$(grep -rno '__STRING_NOT_TRANSLATED__' public/locales/* | wc -l); if [ \"$count\" -gt 0 ]; then echo '❌ Untranslated strings found!'; exit 1; else echo '✅ All strings translated.'; fi",
"check:lookbehind-regex": "count=$(grep -rnoE '\\(\\?<[!=]' .next/static/chunks/* out/_next/static/chunks/* | wc -l); if [ \"$count\" -gt 0 ]; then echo '❌ Lookbehind regex found in output!'; exit 1; else echo '✅ No lookbehind regex found.'; fi",
"check:all": "pnpm check:translations && pnpm check:lookbehind-regex",
"build-check": "pnpm build && pnpm build-web && pnpm check:all"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.735.0",
"@aws-sdk/s3-request-presigner": "^3.735.0",
"@ducanh2912/next-pwa": "^10.2.9",
"@ai-sdk/react": "^3.0.49",
"@assistant-ui/react": "0.11.56",
"@assistant-ui/react-ai-sdk": "1.1.21",
"@assistant-ui/react-markdown": "0.11.9",
"@aws-sdk/client-s3": "^3.1000.0",
"@aws-sdk/s3-request-presigner": "^3.1000.0",
"@choochmeque/tauri-plugin-sharekit-api": "^0.3.0",
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1",
"@fabianlars/tauri-plugin-oauth": "2",
"@opennextjs/cloudflare": "^1.3.1",
"@napi-rs/wasm-runtime": "^1.1.1",
"@opennextjs/cloudflare": "^1.17.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"@serwist/next": "^9.5.6",
"@serwist/webpack-plugin": "^9.5.6",
"@stripe/react-stripe-js": "^3.7.0",
"@stripe/stripe-js": "^7.4.0",
"@supabase/auth-ui-react": "^0.4.7",
"@supabase/auth-ui-shared": "^0.1.8",
"@supabase/supabase-js": "^2.50.2",
"@tauri-apps/api": "2.6.0",
"@tauri-apps/plugin-cli": "^2.3.0",
"@tauri-apps/plugin-deep-link": "^2.3.0",
"@tauri-apps/plugin-dialog": "^2.2.2",
"@tauri-apps/plugin-fs": "^2.3.0",
"@tauri-apps/plugin-haptics": "^2.2.5",
"@tauri-apps/plugin-http": "^2.4.4",
"@tauri-apps/plugin-log": "^2.5.1",
"@tauri-apps/plugin-opener": "^2.3.1",
"@tauri-apps/plugin-os": "^2.2.2",
"@tauri-apps/plugin-process": "^2.2.2",
"@tauri-apps/plugin-shell": "~2.2.2",
"@tauri-apps/plugin-updater": "^2.8.1",
"@zip.js/zip.js": "^2.7.53",
"@supabase/supabase-js": "^2.76.1",
"@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-cli": "^2.4.1",
"@tauri-apps/plugin-deep-link": "^2.4.7",
"@tauri-apps/plugin-dialog": "^2.6.0",
"@tauri-apps/plugin-fs": "^2.4.5",
"@tauri-apps/plugin-haptics": "^2.3.2",
"@tauri-apps/plugin-http": "^2.5.7",
"@tauri-apps/plugin-log": "^2.8.0",
"@tauri-apps/plugin-opener": "^2.5.3",
"@tauri-apps/plugin-os": "^2.3.2",
"@tauri-apps/plugin-process": "^2.3.1",
"@tauri-apps/plugin-shell": "~2.3.5",
"@tauri-apps/plugin-updater": "^2.10.0",
"@tauri-apps/plugin-websocket": "~2.4.2",
"@tursodatabase/database-common": "^0.5.0",
"@tursodatabase/database-wasm": "^0.5.0",
"@tybys/wasm-util": "^0.10.1",
"@zip.js/zip.js": "^2.8.16",
"abortcontroller-polyfill": "^1.7.8",
"ai": "^6.0.47",
"ai-sdk-ollama": "^3.2.0",
"app-store-server-api": "^0.17.1",
"aws4fetch": "^1.0.20",
"buffer": "^6.0.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"cors": "^2.8.5",
"cssbeautify": "^0.3.1",
"dayjs": "^1.11.13",
"dompurify": "^3.3.0",
"foliate-js": "workspace:*",
"franc-min": "^6.2.0",
"fzf": "^0.5.2",
"google-auth-library": "^10.5.0",
"googleapis": "^164.1.0",
"highlight.js": "^11.11.1",
"i18next": "^24.2.0",
"i18next-browser-languagedetector": "^8.0.2",
"i18next-http-backend": "^3.0.1",
"iso-639-2": "^3.0.2",
"iso-639-3": "^3.0.1",
"isomorphic-ws": "^5.0.0",
"js-md5": "^0.8.3",
"jwt-decode": "^4.0.0",
"lucide-react": "^0.562.0",
"lunr": "^2.3.9",
"marked": "^15.0.12",
"next": "15.3.3",
"nanoid": "^5.1.6",
"next": "16.2.2",
"next-view-transitions": "^0.3.5",
"nunjucks": "^3.2.4",
"overlayscrollbars": "^2.11.4",
"overlayscrollbars-react": "^0.5.6",
"posthog-js": "^1.246.0",
"react": "19.0.0",
"react": "19.2.4",
"react-color": "^2.19.3",
"react-dom": "19.0.0",
"react-dom": "19.2.4",
"react-i18next": "^15.2.0",
"react-icons": "^5.4.0",
"react-responsive": "^10.0.0",
"react-virtuoso": "^4.17.0",
"react-window": "^1.8.11",
"remark-gfm": "^4.0.1",
"semver": "^7.7.1",
"streamdown": "^1.6.10",
"stripe": "^18.2.1",
"styled-jsx": "^5.1.7",
"tailwind-merge": "^3.4.0",
"tauri-plugin-device-info-api": "^1.0.1",
"tinycolor2": "^1.6.0",
"zustand": "5.0.1"
"uuid": "^11.1.0",
"ws": "^8.18.3",
"zod": "^4.0.8",
"zustand": "5.0.10"
},
"devDependencies": {
"@next/bundle-analyzer": "^15.4.2",
"@tailwindcss/typography": "^0.5.16",
"@tauri-apps/cli": "2.6.0",
"@tauri-apps/cli": "2.10.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.3.0",
"@tursodatabase/database": "^0.5.0",
"@types/cors": "^2.8.17",
"@types/cssbeautify": "^0.3.5",
"@types/node": "^22.10.1",
"@types/react": "18.3.12",
"@types/lunr": "^2.3.7",
"@types/mocha": "^10.0.10",
"@types/node": "^22.15.31",
"@types/nunjucks": "^3.2.6",
"@types/react": "^19.0.0",
"@types/react-color": "^3.0.13",
"@types/react-dom": "18.3.1",
"@types/react-dom": "^19.0.0",
"@types/react-window": "^1.8.8",
"@types/semver": "^7.7.0",
"@types/tinycolor2": "^1.4.6",
"@types/uuid": "^10.0.0",
"@types/ws": "^8.18.1",
"@typescript/native-preview": "7.0.0-dev.20260312.1",
"@vitejs/plugin-react": "^5.1.1",
"@vitejs/plugin-rsc": "^0.5.21",
"@vitest/browser-playwright": "^4.0.18",
"@vitest/browser-webdriverio": "^4.0.18",
"@vitest/coverage-v8": "^4.0.18",
"@wdio/cli": "^9.25.0",
"@wdio/globals": "^9.23.0",
"@wdio/local-runner": "^9.24.0",
"@wdio/mocha-framework": "^9.24.0",
"@wdio/spec-reporter": "^9.24.0",
"@wdio/types": "^9.24.0",
"autoprefixer": "^10.4.20",
"caniuse-lite": "^1.0.30001746",
"cpx2": "^8.0.0",
"daisyui": "^4.12.24",
"dotenv-cli": "^7.4.4",
"eslint": "^9.16.0",
"eslint-config-next": "15.0.3",
"i18next-scanner": "^4.6.0",
"jsdom": "^28.1.0",
"mkdirp": "^3.0.1",
"node-env-run": "^4.0.2",
"playwright": "^1.58.2",
"postcss": "^8.4.49",
"postcss-cli": "^11.0.0",
"postcss-nested": "^7.0.2",
"raw-loader": "^4.0.2",
"tailwindcss": "^3.4.17",
"react-server-dom-webpack": "^19.2.4",
"serwist": "^9.3.0",
"tailwindcss": "^3.4.18",
"typescript": "^5.7.2",
"wrangler": "^4.21.0"
}
"vinext": "^0.0.21",
"vite": "^7.3.1",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.18",
"wrangler": "^4.77.0"
},
"browserslist": [
"chrome 92",
"edge 92",
"firefox 92",
"safari 15.2"
]
}
@@ -0,0 +1 @@
ed533042-5626-4704-b5f2-fa3bbd1136ed
-2
View File
@@ -1,2 +0,0 @@
/_next/static/*
Cache-Control: public,max-age=31536000,immutable
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,6 @@
"Auto Mode": "Automatischer Modus",
"Behavior": "Verhalten",
"Book": "Buch",
"Book Cover": "Buchcover",
"Bookmark": "Lesezeichen",
"Cancel": "Abbrechen",
"Chapter": "Kapitel",
@@ -46,7 +45,6 @@
"Horizontal Direction": "Horizontale Richtung",
"Hyphenation": "Silbentrennung",
"Import Books": "Bücher importieren",
"Language:": "Sprache:",
"Layout": "Layout",
"Light Mode": "Hellmodus",
"Loading...": "Wird geladen...",
@@ -67,8 +65,8 @@
"Page": "Seite",
"Paging Animation": "Blätter-Animation",
"Paragraph": "Absatz",
"Published:": "Veröffentlicht:",
"Publisher:": "Verlag:",
"Published": "Veröffentlicht",
"Publisher": "Verlag",
"Reading Progress Synced": "Lesevorgang synchronisiert",
"Reload Page": "Seite neu laden",
"Reveal in File Explorer": "Im Datei-Explorer anzeigen",
@@ -82,7 +80,6 @@
"Search...": "Suchen...",
"Select Book": "Buch auswählen",
"Select Books": "Bücher auswählen",
"Select Multiple Books": "Mehrere Bücher auswählen",
"Sepia": "Sepia",
"Serif Font": "Serifenschrift",
"Show Book Details": "Buchdetails anzeigen",
@@ -93,23 +90,21 @@
"Slow": "Langsam",
"Solarized": "Solarisiert",
"Speak": "Sprechen",
"Subjects:": "Themen:",
"Subjects": "Themen",
"System Fonts": "System-Schriftarten",
"TTS not supported in this device": "TTS wird auf diesem Gerät nicht unterstützt",
"Theme Color": "Themenfarbe",
"Theme Mode": "Themenmodus",
"Translate": "Übersetzen",
"Translated Text": "Übersetzter Text",
"Unknown": "Unbekannt",
"Untitled": "Ohne Titel",
"Updated:": "Aktualisiert:",
"Updated": "Aktualisiert",
"Version {{version}}": "Version {{version}}",
"Vertical Direction": "Vertikale Richtung",
"Welcome to your library. You can import your books here and read them anytime.": "Willkommen in Ihrer Bibliothek. Sie können hier Ihre Bücher importieren und jederzeit lesen.",
"Wikipedia": "Wikipedia",
"Writing Mode": "Schreibmodus",
"Your Library": "Ihre Bibliothek",
"TTS not supported for PDF": "TTS wird für PDF nicht unterstützt",
"Override Book Font": "Buch-Schriftart überschreiben",
"Apply to All Books": "Auf alle Bücher anwenden",
"Apply to This Book": "Auf dieses Buch anwenden",
@@ -119,6 +114,7 @@
"Book Details": "Buchdetails",
"From Local File": "Aus lokaler Datei",
"TOC": "Inhaltsverzeichnis",
"Table of Contents": "Inhaltsverzeichnis",
"Book uploaded: {{title}}": "Buch hochgeladen: {{title}}",
"Failed to upload book: {{title}}": "Fehler beim Hochladen des Buches: {{title}}",
"Book downloaded: {{title}}": "Buch heruntergeladen: {{title}}",
@@ -175,9 +171,6 @@
"Token": "Token",
"Your OTP token": "Ihr OTP-Token",
"Verify token": "Token überprüfen",
"Sign in with Google": "Mit Google anmelden",
"Sign in with Apple": "Mit Apple anmelden",
"Sign in with GitHub": "Mit GitHub anmelden",
"Account": "Konto",
"Failed to delete user. Please try again later.": "Benutzer konnte nicht gelöscht werden. Bitte versuchen Sie es später erneut.",
"Community Support": "Community-Support",
@@ -190,12 +183,11 @@
"RTL Direction": "RTL-Richtung",
"Maximum Column Height": "Maximale Spaltenhöhe",
"Maximum Column Width": "Maximale Spaltenbreite",
"Continuous Scroll": "Kontinuierliches Scrollen",
"Fullscreen": "Vollbild",
"No supported files found. Supported formats: {{formats}}": "Keine unterstützten Dateien gefunden. Unterstützte Formate: {{formats}}",
"Drop to Import Books": "Zum Importieren von Büchern ablegen",
"Custom": "Eigen",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Die ganze Welt ist eine Bühne,\nUnd alle Männer und Frauen sind bloß Spieler;\nSie haben ihre Abgänge und ihre Auftritte,\nUnd ein Mann spielt in seinem Leben viele Rollen,\nSeine Taten sind sieben Zeitalter.\n\n—William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Die ganze Welt ist eine Bühne,\nUnd alle Männer und Frauen sind bloß Spieler;\nSie haben ihre Abgänge und ihre Auftritte,\nUnd ein Mann spielt in seinem Leben viele Rollen,\nSeine Taten sind sieben Zeitalter.\n\n— William Shakespeare",
"Custom Theme": "Benutzerdefiniertes Thema",
"Theme Name": "Themenname",
"Text Color": "Textfarbe",
@@ -222,9 +214,9 @@
"Auto Import on File Open": "Automatischer Import beim Öffnen einer Datei",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "Keine Kapitel erkannt.",
"Failed to parse the EPUB file.": "Fehler beim Parsen der EPUB-Datei.",
"This book format is not supported.": "Dieses Buchformat wird nicht unterstützt.",
"No chapters detected": "Keine Kapitel erkannt",
"Failed to parse the EPUB file": "Fehler beim Parsen der EPUB-Datei",
"This book format is not supported": "Dieses Buchformat wird nicht unterstützt",
"Unable to fetch the translation. Please log in first and try again.": "Übersetzung konnte nicht abgerufen werden. Bitte zuerst anmelden und erneut versuchen.",
"Group": "Gruppieren",
"Always on Top": "Immer im Vordergrund",
@@ -243,7 +235,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "Herunterladen {{downloaded}} von {{contentLength}}",
"Download finished": "Download abgeschlossen",
"DOWNLOAD & INSTALL": "HERUNTERLADEN & INSTALLIEREN",
"Changelog:": "Änderungsprotokoll:",
"Changelog": "Änderungsprotokoll",
"Software Update": "Software-Update",
"Title": "Titel",
"Date Read": "Datum gelesen",
@@ -252,18 +244,15 @@
"Ascending": "Aufsteigend",
"Descending": "Absteigend",
"Sort by...": "Sortieren nach...",
"Added:": "Hinzugefügt:",
"Format:": "Format:",
"Added": "Hinzugefügt",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "Beschreibung:",
"Description": "Beschreibung",
"No description available": "Keine Beschreibung verfügbar",
"List": "Liste",
"Grid": "Raster",
"(from 'As You Like It', Act II)": "(aus 'Wie es euch gefällt', Akt II)",
"Link Color": "Linkfarbe",
"Volume Keys for Page Flip": "Volumen-Tasten für Seitenwechsel",
"Clicks for Page Flip": "Tippen zum Blättern",
"Swap Clicks Area": "Tippbereiche tauschen",
"Screen": "Bildschirm",
"Orientation": "Orientierung",
"Portrait": "Hochformat",
@@ -272,7 +261,7 @@
"Checking for updates...": "Auf Updates prüfen...",
"Error checking for updates": "Fehler beim Überprüfen auf Updates",
"Details": "Details",
"File Size:": "Dateigröße:",
"File Size": "Dateigröße",
"Auto Detect": "Automatisch erkennen",
"Next Section": "Nächster Abschnitt",
"Previous Section": "Vorheriger Abschnitt",
@@ -299,7 +288,6 @@
"Disable Translation": "Übersetzung deaktivieren",
"Scroll": "Scrollen",
"Overlap Pixels": "Überlappungspixel",
"Click": "Tippen",
"System Language": "Systemsprache",
"Security": "Sicherheit",
"Allow JavaScript": "JavaScript zulassen",
@@ -313,7 +301,6 @@
"Synced at {{time}}": "Synchronisiert um {{time}}",
"Never synced": "Nie synchronisiert",
"Show Remaining Time": "Verbleibende Zeit anzeigen",
"Show Page Number": "Seitenzahl anzeigen",
"{{time}} min left in chapter": "{{time}} min verbleibend im Kapitel",
"Override Book Color": "Farbe des Buches überschreiben",
"Login Required": "Anmeldung nötig",
@@ -336,7 +323,6 @@
"Left Margin (px)": "Linker Rand (px)",
"Column Gap (%)": "Spaltenabstand (%)",
"Always Show Status Bar": "Statusleiste immer anzeigen",
"Translation Not Available": "Übersetzung nicht verfügbar",
"Custom Content CSS": "Benutzerdefiniertes Inhalts-CSS",
"Enter CSS for book content styling...": "CSS für die Buchinhaltsgestaltung eingeben...",
"Custom Reader UI CSS": "Benutzerdefiniertes CSS für die Leseroberfläche",
@@ -346,11 +332,11 @@
"Fit": "Anpassen",
"Reset {{settings}}": "{{settings}} zurücksetzen",
"Reset Settings": "Einstellungen zurücksetzen",
"{{count}} pages left in chapter_one": "{{count}} Seite verbleibend im Kapitel",
"{{count}} pages left in chapter_other": "{{count}} Seiten verbleibend im Kapitel",
"{{count}} pages left in chapter_one": "<0>{{count}}</0><1> Seite verbleibend im Kapitel</1>",
"{{count}} pages left in chapter_other": "<0>{{count}}</0><1> Seiten verbleibend im Kapitel</1>",
"Show Remaining Pages": "Verbleibende Seiten anzeigen",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Abo verwalten",
"Coming Soon": "Demnächst verfügbar",
@@ -358,7 +344,6 @@
"Upgrade to Plus or Pro": "Upgrade auf Plus oder Pro",
"Current Plan": "Aktueller Tarif",
"Plan Limits": "Tariflimits",
"Failed to manage subscription. Please try again later.": "Verwaltung des Abos fehlgeschlagen. Bitte versuchen Sie es später erneut.",
"Processing your payment...": "Zahlung wird verarbeitet...",
"Please wait while we confirm your subscription.": "Bitte warten Sie, während wir Ihr Abo bestätigen.",
"Payment Processing": "Zahlung wird verarbeitet",
@@ -371,7 +356,6 @@
"Email:": "E-Mail:",
"Plan:": "Tarif:",
"Amount:": "Betrag:",
"Subscription ID:": "Abo-ID:",
"Go to Library": "Zur Bibliothek",
"Need help? Contact our support team at support@readest.com": "Brauchen Sie Hilfe? Kontaktieren Sie unser Support-Team unter support@readest.com",
"Free Plan": "Gratis-Tarif",
@@ -400,7 +384,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "Beliebig viel Text in Audio umwandeln.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Erweitere Übersetzungen und tägliches Kontingent.",
"DeepL Pro Access": "DeepL Pro-Zugang",
"2 GB Cloud Sync Storage": "2 GB Cloud-Speicher",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Erhalte schnellen, persönlichen Support.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Tageslimit erreicht. Upgrade nötig, um weiter zu übersetzen.",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "Personalisieren Sie jedes Detail mit anpassbaren Schriften, Layouts, Themes und erweiterten Anzeigeeinstellungen für das perfekte Leseerlebnis.",
@@ -412,10 +395,793 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Nutzen Sie leistungsstarke KI-Tools für intelligenteres Lesen, Übersetzen und Content-Discovery.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Übersetzen Sie täglich bis zu 100.000 Zeichen mit der genauesten verfügbaren Übersetzungsmaschine.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Übersetzen Sie täglich bis zu 500.000 Zeichen mit der genauesten verfügbaren Übersetzungsmaschine.",
"10 GB Cloud Sync Storage": "10 GB Cloud-Sync-Speicher",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "Speichern und greifen Sie sicher auf Ihre gesamte Lesekollektion mit bis zu 2 GB Cloud-Speicher zu.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "Speichern und greifen Sie sicher auf Ihre gesamte Lesekollektion mit bis zu 10 GB Cloud-Speicher zu.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Speichern und greifen Sie sicher auf Ihre gesamte Lesekollektion mit bis zu 5 GB Cloud-Speicher zu.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Speichern und greifen Sie sicher auf Ihre gesamte Lesekollektion mit bis zu 20 GB Cloud-Speicher zu.",
"Deleted cloud backup of the book: {{title}}": "Gelöschte Cloud-Sicherung des Buches: {{title}}",
"Failed to delete cloud backup of the book": "Fehler beim Löschen der Cloud-Sicherung des Buches",
"Are you sure to delete the cloud backup of the selected book?": "Sind Sie sicher, dass Sie die Cloud-Sicherung des ausgewählten Buches löschen möchten?"
"Are you sure to delete the cloud backup of the selected book?": "Sind Sie sicher, dass Sie die Cloud-Sicherung des ausgewählten Buches löschen möchten?",
"What's New in Readest": "Was gibt es Neues in Readest",
"Enter book title": "Buchtitel eingeben",
"Subtitle": "Untertitel",
"Enter book subtitle": "Buchuntertitel eingeben",
"Enter author name": "Autorennamen eingeben",
"Series": "Serie",
"Enter series name": "Seriennamen eingeben",
"Series Index": "Seriennummer",
"Enter series index": "Seriennummer eingeben",
"Total in Series": "Gesamt in Serie",
"Enter total books in series": "Gesamtanzahl der Bücher in Serie eingeben",
"Enter publisher": "Verlag eingeben",
"Publication Date": "Veröffentlichungsdatum",
"Identifier": "Identifikator",
"Enter book description": "Buchbeschreibung eingeben",
"Change cover image": "Titelbild ändern",
"Replace": "Ersetzen",
"Unlock cover": "Titelbild entsperren",
"Lock cover": "Titelbild sperren",
"Auto-Retrieve Metadata": "Metadaten automatisch abrufen",
"Auto-Retrieve": "Automatisch abrufen",
"Unlock all fields": "Alle Felder entsperren",
"Unlock All": "Alle entsperren",
"Lock all fields": "Alle Felder sperren",
"Lock All": "Alle sperren",
"Reset": "Zurücksetzen",
"Edit Metadata": "Metadaten bearbeiten",
"Locked": "Gesperrt",
"Select Metadata Source": "Metadatenquelle auswählen",
"Keep manual input": "Manuelle Eingabe beibehalten",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Belletristik, Wissenschaft, Geschichte",
"Open Book in New Window": "Buch in neuem Fenster öffnen",
"Voices for {{lang}}": "Stimmen für {{lang}}",
"Yandex Translate": "Yandex Übersetzer",
"YYYY or YYYY-MM-DD": "YYYY oder YYYY-MM-DD",
"Restore Purchase": "Kauf wiederherstellen",
"No purchases found to restore.": "Keine Käufe zum Wiederherstellen gefunden.",
"Failed to restore purchases.": "Wiederherstellung der Käufe fehlgeschlagen.",
"Failed to manage subscription.": "Verwaltung des Abonnements fehlgeschlagen.",
"Failed to load subscription plans.": "Laden der Abonnementpläne fehlgeschlagen.",
"year": "Jahr",
"Failed to create checkout session": "Fehler beim Erstellen der Checkout-Sitzung",
"Storage": "Speicher",
"Terms of Service": "Allgemeine Geschäftsbedingungen",
"Privacy Policy": "Datenschutzbestimmungen",
"Disable Double Click": "Doppelklick deaktivieren",
"TTS not supported for this document": "TTS wird für dieses Dokument nicht unterstützt",
"Reset Password": "Passwort zurücksetzen",
"Show Reading Progress": "Lesefortschritt anzeigen",
"Reading Progress Style": "Lesefortschritt-Stil",
"Page Number": "Seitenzahl",
"Percentage": "Prozentsatz",
"Deleted local copy of the book: {{title}}": "Gelöschte lokale Kopie des Buches: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Fehler beim Löschen der Cloud-Sicherung des Buches: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Fehler beim Löschen der lokalen Kopie des Buches: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Sind Sie sicher, dass Sie die lokale Kopie des ausgewählten Buches löschen möchten?",
"Remove from Cloud & Device": "Aus Cloud & Gerät entfernen",
"Remove from Cloud Only": "Nur aus der Cloud entfernen",
"Remove from Device Only": "Nur vom Gerät entfernen",
"Disconnected": "Getrennt",
"KOReader Sync Settings": "KOReader Sync-Einstellungen",
"Sync Strategy": "Sync-Strategie",
"Ask on conflict": "Bei Konflikten fragen",
"Always use latest": "Immer die neueste Version verwenden",
"Send changes only": "Nur Änderungen senden",
"Receive changes only": "Nur Änderungen empfangen",
"Checksum Method": "Prüfziffernverfahren",
"File Content (recommended)": "Dateiinhalte (empfohlen)",
"File Name": "Dateiname",
"Device Name": "Gerätename",
"Connect to your KOReader Sync server.": "Mit Ihrem KOReader Sync-Server verbinden.",
"Server URL": "Server-URL",
"Username": "Benutzername",
"Your Username": "Ihr Benutzername",
"Password": "Passwort",
"Connect": "Verbinden",
"KOReader Sync": "KOReader Sync",
"Sync Conflict": "Sync-Konflikt",
"Sync reading progress from \"{{deviceName}}\"?": "Lesefortschritt von \"{{deviceName}}\" synchronisieren?",
"another device": "ein anderes Gerät",
"Local Progress": "Lokaler Fortschritt",
"Remote Progress": "Entfernter Fortschritt",
"Page {{page}} of {{total}} ({{percentage}}%)": "Seite {{page}} von {{total}} ({{percentage}}%)",
"Current position": "Aktuelle Position",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Ungefähr Seite {{page}} von {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Ungefähr {{percentage}}%",
"Failed to connect": "Verbindung fehlgeschlagen",
"Sync Server Connected": "Sync-Server verbunden",
"Sync as {{userDisplayName}}": "Sync als {{userDisplayName}}",
"Custom Fonts": "Benutzerdefinierte Schriftarten",
"Cancel Delete": "Löschen abbrechen",
"Import Font": "Schriftart importieren",
"Delete Font": "Schriftart löschen",
"Tips": "Tipps",
"Custom fonts can be selected from the Font Face menu": "Benutzerdefinierte Schriftarten können aus dem Schriftart-Menü ausgewählt werden",
"Manage Custom Fonts": "Benutzerdefinierte Schriftarten verwalten",
"Select Files": "Dateien auswählen",
"Select Image": "Bild auswählen",
"Select Video": "Video auswählen",
"Select Audio": "Audio auswählen",
"Select Fonts": "Schriftarten auswählen",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Unterstützte Schriftartenformate: .ttf, .otf, .woff, .woff2",
"Push Progress": "Fortschritt senden",
"Pull Progress": "Fortschritt empfangen",
"Previous Paragraph": "Vorheriger Absatz",
"Previous Sentence": "Vorheriger Satz",
"Pause": "Pause",
"Play": "Wiedergabe",
"Next Sentence": "Nächster Satz",
"Next Paragraph": "Nächster Absatz",
"Separate Cover Page": "Titelseite separat anzeigen",
"Resize Notebook": "Notizbuchgröße ändern",
"Resize Sidebar": "Seitenleisten-Größe ändern",
"Get Help from the Readest Community": "Hilfe von der Readest-Community erhalten",
"Remove cover image": "Coverbild entfernen",
"Bookshelf": "Bücherregal",
"View Menu": "Menü anzeigen",
"Settings Menu": "Einstellungsmenü",
"View account details and quota": "Kontodetails und Kontingent anzeigen",
"Library Header": "Bibliothekskopf",
"Book Content": "Buchinhalt",
"Footer Bar": "Fußzeile",
"Header Bar": "Kopfzeile",
"View Options": "Ansichtsoptionen",
"Book Menu": "Buchmenü",
"Search Options": "Suchoptionen",
"Close": "Schließen",
"Delete Book Options": "Buch-Löschoptionen",
"ON": "EIN",
"OFF": "AUS",
"Reading Progress": "Lesefortschritt",
"Page Margin": "Seitenrand",
"Remove Bookmark": "Lesezeichen entfernen",
"Add Bookmark": "Lesezeichen hinzufügen",
"Books Content": "Buchinhalt",
"Jump to Location": "Zu Standort springen",
"Unpin Notebook": "Notizbuch lösen",
"Pin Notebook": "Notizbuch anheften",
"Hide Search Bar": "Suchleiste ausblenden",
"Show Search Bar": "Suchleiste einblenden",
"On {{current}} of {{total}} page": "Auf Seite {{current}} von {{total}}",
"Section Title": "Abschnittsüberschrift",
"Decrease": "Verringern",
"Increase": "Erhöhen",
"Settings Panels": "Einstellungsfenster",
"Settings": "Einstellungen",
"Unpin Sidebar": "Seitenleiste lösen",
"Pin Sidebar": "Seitenleiste anheften",
"Toggle Sidebar": "Seitenleiste umschalten",
"Toggle Translation": "Übersetzung umschalten",
"Translation Disabled": "Übersetzung deaktiviert",
"Minimize": "Minimieren",
"Maximize or Restore": "Maximieren oder Wiederherstellen",
"Exit Parallel Read": "Parallel Read beenden",
"Enter Parallel Read": "Parallel Read starten",
"Zoom Level": "Zoomstufe",
"Zoom Out": "Hineinzoomen",
"Reset Zoom": "Zoom zurücksetzen",
"Zoom In": "Herauszoomen",
"Zoom Mode": "Zoom-Modus",
"Single Page": "Einzelne Seite",
"Auto Spread": "Automatische Verbreitung",
"Fit Page": "Seite anpassen",
"Fit Width": "Breite anpassen",
"Failed to select directory": "Fehler beim Auswählen des Verzeichnisses",
"The new data directory must be different from the current one.": "Das neue Datenverzeichnis muss sich vom aktuellen unterscheiden.",
"Migration failed: {{error}}": "Migration fehlgeschlagen: {{error}}",
"Change Data Location": "Datenstandort ändern",
"Current Data Location": "Aktueller Datenstandort",
"Total size: {{size}}": "Gesamtgröße: {{size}}",
"Calculating file info...": "Dateiinformationen werden berechnet...",
"New Data Location": "Neuer Datenstandort",
"Choose Different Folder": "Anderen Ordner wählen",
"Choose New Folder": "Neuen Ordner wählen",
"Migrating data...": "Daten werden migriert...",
"Copying: {{file}}": "Kopiere: {{file}}",
"{{current}} of {{total}} files": "{{current}} von {{total}} Dateien",
"Migration completed successfully!": "Migration erfolgreich abgeschlossen!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Ihre Daten wurden an den neuen Speicherort verschoben. Bitte starten Sie die Anwendung neu, um den Vorgang abzuschließen.",
"Migration failed": "Migration fehlgeschlagen",
"Important Notice": "Wichtiger Hinweis",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Dies wird alle Ihre App-Daten an den neuen Speicherort verschieben. Stellen Sie sicher, dass das Ziel über ausreichend freien Speicherplatz verfügt.",
"Restart App": "App neu starten",
"Start Migration": "Migration starten",
"Advanced Settings": "Erweiterte Einstellungen",
"File count: {{size}}": "Dateianzahl: {{size}}",
"Background Read Aloud": "Hintergrund-Vorlesen",
"Ready to read aloud": "Bereit zum Vorlesen",
"Read Aloud": "Vorlesen",
"Screen Brightness": "Bildschirmhelligkeit",
"Background Image": "Hintergrundbild",
"Import Image": "Bild importieren",
"Opacity": "Opazität",
"Size": "Größe",
"Cover": "Cover",
"Contain": "Inhalt",
"{{number}} pages left in chapter": "<0>{{number}}</0><1> Seiten verbleibend im Kapitel</1>",
"Device": "Gerät",
"E-Ink Mode": "E-Ink-Modus",
"Highlight Colors": "Hervorhebungsfarben",
"Pagination": "Seitenumbruch",
"Disable Double Tap": "Doppeltippen deaktivieren",
"Tap to Paginate": "Tippen zum Blättern",
"Click to Paginate": "Klicken zum Blättern",
"Tap Both Sides": "Tippen Sie auf beide Seiten",
"Click Both Sides": "Klicken Sie auf beide Seiten",
"Swap Tap Sides": "Seiten für das Tippen tauschen",
"Swap Click Sides": "Seiten für das Klicken tauschen",
"Source and Translated": "Quell- und Übersetzungstext",
"Translated Only": "Nur Übersetzungstext",
"Source Only": "Nur Quelltext",
"TTS Text": "TTS-Text",
"The book file is corrupted": "Die Buchdatei ist beschädigt",
"The book file is empty": "Die Buchdatei ist leer",
"Failed to open the book file": "Fehler beim Öffnen der Buchdatei",
"On-Demand Purchase": "Kauf auf Anfrage",
"Full Customization": "Vollständige Anpassung",
"Lifetime Plan": "Lebenslange Planung",
"One-Time Payment": "Einmalige Zahlung",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Zahlen Sie einmalig, um lebenslangen Zugriff auf bestimmte Funktionen auf allen Geräten zu genießen. Kaufen Sie bestimmte Funktionen oder Dienstleistungen nur, wenn Sie sie benötigen.",
"Expand Cloud Sync Storage": "Cloud-Synchronisierungs-Speicher erweitern",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Erweitern Sie Ihren Cloud-Speicher für immer mit einem einmaligen Kauf. Jeder zusätzliche Kauf fügt mehr Speicherplatz hinzu.",
"Unlock All Customization Options": "Alle Anpassungsoptionen freischalten",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Zusätzliche Themen, Schriftarten, Layoutoptionen und Vorlesefunktionen, Übersetzer, Cloud-Speicherdienste freischalten.",
"Purchase Successful!": "Kauf erfolgreich!",
"lifetime": "lebenslang",
"Thank you for your purchase! Your payment has been processed successfully.": "Danke für Ihren Kauf! Ihre Zahlung wurde erfolgreich verarbeitet.",
"Order ID:": "Bestell-ID:",
"TTS Highlighting": "TTS-Hervorhebung",
"Style": "Stil",
"Underline": "Unterstreichen",
"Strikethrough": "Durchgestrichen",
"Squiggly": "Wellig",
"Outline": "Umriss",
"Save Current Color": "Aktuelle Farbe speichern",
"Quick Colors": "Schnellfarben",
"Highlighter": "Textmarker",
"Save Book Cover": "Buchcover speichern",
"Auto-save last book cover": "Letztes Buchcover automatisch speichern",
"Back": "Zurück",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Bestätigungs-E-Mail gesendet! Bitte überprüfe deine alte und neue E-Mail-Adresse, um die Änderung zu bestätigen.",
"Failed to update email": "E-Mail konnte nicht aktualisiert werden",
"New Email": "Neue E-Mail",
"Your new email": "Deine neue E-Mail-Adresse",
"Updating email ...": "E-Mail wird aktualisiert ...",
"Update email": "E-Mail aktualisieren",
"Current email": "Aktuelle E-Mail",
"Update Email": "E-Mail aktualisieren",
"All": "Alle",
"Unable to open book": "Buch kann nicht geöffnet werden",
"Punctuation": "Interpunktion",
"Replace Quotation Marks": "Anführungszeichen ersetzen",
"Enabled only in vertical layout.": "Nur im vertikalen Layout aktiviert.",
"No Conversion": "Keine Konvertierung",
"Simplified to Traditional": "Vereinfacht → Traditionell",
"Traditional to Simplified": "Traditionell → Vereinfacht",
"Simplified to Traditional (Taiwan)": "Vereinfacht → Traditionell (Taiwan)",
"Simplified to Traditional (Hong Kong)": "Vereinfacht → Traditionell (Hongkong)",
"Simplified to Traditional (Taiwan), with phrases": "Vereinfacht → Traditionell (Taiwan • Phrasen)",
"Traditional (Taiwan) to Simplified": "Traditionell (Taiwan) → Vereinfacht",
"Traditional (Hong Kong) to Simplified": "Traditionell (Hongkong) → Vereinfacht",
"Traditional (Taiwan) to Simplified, with phrases": "Traditionell (Taiwan • Phrasen) → Vereinfacht",
"Convert Simplified and Traditional Chinese": "Vereinfach./Traditionell konvertieren",
"Convert Mode": "Konvertierungsmodus",
"Failed to auto-save book cover for lock screen: {{error}}": "Automatisches Speichern des Buchcovers für den Sperrbildschirm fehlgeschlagen: {{error}}",
"Download from Cloud": "Aus der Cloud herunterladen",
"Upload to Cloud": "In die Cloud hochladen",
"Clear Custom Fonts": "Benutzerdefinierte Schriftarten löschen",
"Columns": "Spalten",
"OPDS Catalogs": "OPDS-Kataloge",
"Adding LAN addresses is not supported in the web app version.": "Das Hinzufügen von LAN-Adressen wird in der Web-App nicht unterstützt.",
"Invalid OPDS catalog. Please check the URL.": "Ungültiger OPDS-Katalog. Bitte überprüfe die URL.",
"Browse and download books from online catalogs": "Bücher aus Online-Katalogen durchsuchen und herunterladen",
"My Catalogs": "Meine Kataloge",
"Add Catalog": "Katalog hinzufügen",
"No catalogs yet": "Noch keine Kataloge",
"Add your first OPDS catalog to start browsing books": "Füge deinen ersten OPDS-Katalog hinzu, um Bücher zu durchsuchen.",
"Add Your First Catalog": "Ersten Katalog hinzufügen",
"Browse": "Durchsuchen",
"Popular Catalogs": "Beliebte Kataloge",
"Add": "Hinzufügen",
"Add OPDS Catalog": "OPDS-Katalog hinzufügen",
"Catalog Name": "Katalogname",
"My Calibre Library": "Meine Calibre-Bibliothek",
"OPDS URL": "OPDS-URL",
"Username (optional)": "Benutzername (optional)",
"Password (optional)": "Passwort (optional)",
"Description (optional)": "Beschreibung (optional)",
"A brief description of this catalog": "Kurzbeschreibung dieses Katalogs",
"Validating...": "Wird überprüft...",
"View All": "Alle anzeigen",
"Forward": "Weiter",
"Home": "Start",
"{{count}} items_one": "{{count}} Element",
"{{count}} items_other": "{{count}} Elemente",
"Download completed": "Download abgeschlossen",
"Download failed": "Download fehlgeschlagen",
"Open Access": "Offener Zugriff",
"Borrow": "Ausleihen",
"Buy": "Kaufen",
"Subscribe": "Abonnieren",
"Sample": "Leseprobe",
"Download": "Herunterladen",
"Open & Read": "Öffnen & Lesen",
"Tags": "Tags",
"Tag": "Tag",
"First": "Erste",
"Previous": "Vorherige",
"Next": "Nächste",
"Last": "Letzte",
"Cannot Load Page": "Seite kann nicht geladen werden",
"An error occurred": "Ein Fehler ist aufgetreten",
"Online Library": "Online-Bibliothek",
"URL must start with http:// or https://": "Die URL muss mit http:// oder https:// beginnen",
"Title, Author, Tag, etc...": "Titel, Autor, Tag, etc...",
"Query": "Suchbegriff",
"Subject": "Thema",
"Enter {{terms}}": "Gib {{terms}} ein",
"No search results found": "Keine Suchergebnisse gefunden",
"Failed to load OPDS feed: {{status}} {{statusText}}": "OPDS-Feed konnte nicht geladen werden: {{status}} {{statusText}}",
"Search in {{title}}": "Suche in {{title}}",
"Manage Storage": "Speicher verwalten",
"Failed to load files": "Dateien konnten nicht geladen werden",
"Deleted {{count}} file(s)_one": "{{count}} Datei gelöscht",
"Deleted {{count}} file(s)_other": "{{count}} Dateien gelöscht",
"Failed to delete {{count}} file(s)_one": "Löschen von {{count}} Datei fehlgeschlagen",
"Failed to delete {{count}} file(s)_other": "Löschen von {{count}} Dateien fehlgeschlagen",
"Failed to delete files": "Dateien konnten nicht gelöscht werden",
"Total Files": "Gesamtdateien",
"Total Size": "Gesamtgröße",
"Quota": "Kontingent",
"Used": "Verwendet",
"Files": "Dateien",
"Search files...": "Dateien suchen...",
"Newest First": "Neueste zuerst",
"Oldest First": "Älteste zuerst",
"Largest First": "Größte zuerst",
"Smallest First": "Kleinste zuerst",
"Name A-Z": "Name AZ",
"Name Z-A": "Name ZA",
"{{count}} selected_one": "{{count}} ausgewählt",
"{{count}} selected_other": "{{count}} ausgewählt",
"Delete Selected": "Ausgewählte löschen",
"Created": "Erstellt",
"No files found": "Keine Dateien gefunden",
"No files uploaded yet": "Noch keine Dateien hochgeladen",
"files": "Dateien",
"Page {{current}} of {{total}}": "Seite {{current}} von {{total}}",
"Are you sure to delete {{count}} selected file(s)?_one": "Möchten Sie {{count}} ausgewählte Datei wirklich löschen?",
"Are you sure to delete {{count}} selected file(s)?_other": "Möchten Sie {{count}} ausgewählte Dateien wirklich löschen?",
"Cloud Storage Usage": "Cloud-Speichernutzung",
"Rename Group": "Gruppe umbenennen",
"From Directory": "Aus Verzeichnis",
"Successfully imported {{count}} book(s)_one": "Erfolgreich 1 Buch importiert",
"Successfully imported {{count}} book(s)_other": "Erfolgreich {{count}} Bücher importiert",
"Count": "Anzahl",
"Start Page": "Startseite",
"Search in OPDS Catalog...": "Im OPDS-Katalog suchen...",
"Please log in to use advanced TTS features": "Bitte melde dich an, um erweiterte TTS-Funktionen zu nutzen",
"Word limit of 30 words exceeded.": "Das Wortlimit von 30 Wörtern wurde überschritten.",
"Proofread": "Korrekturlesen",
"Current selection": "Aktuelle Auswahl",
"All occurrences in this book": "Alle Vorkommen in diesem Buch",
"All occurrences in your library": "Alle Vorkommen in Ihrer Bibliothek",
"Selected text:": "Ausgewählter Text:",
"Replace with:": "Ersetzen durch:",
"Enter text...": "Text eingeben …",
"Case sensitive:": "Groß-/Kleinschreibung:",
"Scope:": "Geltungsbereich:",
"Selection": "Auswahl",
"Library": "Bibliothek",
"Yes": "Ja",
"No": "Nein",
"Proofread Replacement Rules": "Korrektur-Ersetzungsregeln",
"Selected Text Rules": "Regeln für ausgewählten Text",
"No selected text replacement rules": "Keine Ersetzungsregeln für ausgewählten Text",
"Book Specific Rules": "Buchspezifische Regeln",
"No book-level replacement rules": "Keine Ersetzungsregeln auf Buchebene",
"Disable Quick Action": "Schnellaktion deaktivieren",
"Enable Quick Action on Selection": "Schnellaktion bei Auswahl aktivieren",
"None": "Keine",
"Annotation Tools": "Anmerkungswerkzeuge",
"Enable Quick Actions": "Schnellaktionen aktivieren",
"Quick Action": "Schnellaktion",
"Copy to Notebook": "In Notizbuch kopieren",
"Copy text after selection": "Text nach Auswahl kopieren",
"Highlight text after selection": "Text nach Auswahl hervorheben",
"Annotate text after selection": "Text nach Auswahl annotieren",
"Search text after selection": "Text nach Auswahl suchen",
"Look up text in dictionary after selection": "Text nach Auswahl im Wörterbuch nachschlagen",
"Look up text in Wikipedia after selection": "Text nach Auswahl in Wikipedia nachschlagen",
"Translate text after selection": "Text nach Auswahl übersetzen",
"Read text aloud after selection": "Text nach Auswahl vorlesen",
"Proofread text after selection": "Text nach Auswahl Korrektur lesen",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} aktiv, {{pendingCount}} ausstehend",
"{{failedCount}} failed": "{{failedCount}} fehlgeschlagen",
"Waiting...": "Warten...",
"Failed": "Fehlgeschlagen",
"Completed": "Abgeschlossen",
"Cancelled": "Abgebrochen",
"Retry": "Erneut versuchen",
"Active": "Aktiv",
"Transfer Queue": "Übertragungswarteschlange",
"Upload All": "Alle hochladen",
"Download All": "Alle herunterladen",
"Resume Transfers": "Übertragungen fortsetzen",
"Pause Transfers": "Übertragungen pausieren",
"Pending": "Ausstehend",
"No transfers": "Keine Übertragungen",
"Retry All": "Alle erneut versuchen",
"Clear Completed": "Abgeschlossene löschen",
"Clear Failed": "Fehlgeschlagene löschen",
"Upload queued: {{title}}": "Upload in Warteschlange: {{title}}",
"Download queued: {{title}}": "Download in Warteschlange: {{title}}",
"Book not found in library": "Buch nicht in der Bibliothek gefunden",
"Unknown error": "Unbekannter Fehler",
"Please log in to continue": "Bitte melden Sie sich an, um fortzufahren",
"Cloud File Transfers": "Cloud-Dateiübertragungen",
"Show Search Results": "Suchergebnisse anzeigen",
"Search results for '{{term}}'": "Ergebnisse für '{{term}}'",
"Close Search": "Suche schließen",
"Previous Result": "Vorheriges Ergebnis",
"Next Result": "Nächstes Ergebnis",
"Bookmarks": "Lesezeichen",
"Annotations": "Anmerkungen",
"Show Results": "Ergebnisse anzeigen",
"Clear search": "Suche löschen",
"Clear search history": "Suchverlauf löschen",
"Tap to Toggle Footer": "Tippen, um Fußzeile umzuschalten",
"Show Current Time": "Aktuelle Uhrzeit anzeigen",
"Use 24 Hour Clock": "24-Stunden-Format verwenden",
"Show Current Battery Status": "Aktuellen Akkustand anzeigen",
"Exported successfully": "Erfolgreich exportiert",
"Book exported successfully.": "Buch erfolgreich exportiert.",
"Failed to export the book.": "Buch konnte nicht exportiert werden.",
"Export Book": "Buch exportieren",
"Whole word:": "Ganzes Wort:",
"Error": "Fehler",
"Unable to load the article. Try searching directly on {{link}}.": "Artikel kann nicht geladen werden. Versuchen Sie die direkte Suche auf {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Wort kann nicht geladen werden. Versuchen Sie die direkte Suche auf {{link}}.",
"Date Published": "Veröffentlichungsdatum",
"Only for TTS:": "Nur für TTS:",
"Uploaded": "Hochgeladen",
"Downloaded": "Heruntergeladen",
"Deleted": "Gelöscht",
"Note:": "Notiz:",
"Time:": "Zeit:",
"Format Options": "Formatoptionen",
"Export Date": "Exportdatum",
"Chapter Titles": "Kapiteltitel",
"Chapter Separator": "Kapiteltrennzeichen",
"Highlights": "Markierungen",
"Note Date": "Notizdatum",
"Advanced": "Erweitert",
"Hide": "Ausblenden",
"Show": "Anzeigen",
"Use Custom Template": "Benutzerdefinierte Vorlage verwenden",
"Export Template": "Exportvorlage",
"Template Syntax:": "Vorlagensyntax:",
"Insert value": "Wert einfügen",
"Format date (locale)": "Datum formatieren (Gebietsschema)",
"Format date (custom)": "Datum formatieren (benutzerdefiniert)",
"Conditional": "Bedingung",
"Loop": "Schleife",
"Available Variables:": "Verfügbare Variablen:",
"Book title": "Buchtitel",
"Book author": "Buchautor",
"Export date": "Exportdatum",
"Array of chapters": "Array von Kapiteln",
"Chapter title": "Kapiteltitel",
"Array of annotations": "Array von Anmerkungen",
"Highlighted text": "Markierter Text",
"Annotation note": "Anmerkungsnotiz",
"Date Format Tokens:": "Datumsformat-Token:",
"Year (4 digits)": "Jahr (4 Ziffern)",
"Month (01-12)": "Monat (01-12)",
"Day (01-31)": "Tag (01-31)",
"Hour (00-23)": "Stunde (00-23)",
"Minute (00-59)": "Minute (00-59)",
"Second (00-59)": "Sekunde (00-59)",
"Show Source": "Quelle anzeigen",
"No content to preview": "Kein Inhalt zur Vorschau",
"Export": "Exportieren",
"Set Timeout": "Zeitlimit festlegen",
"Select Voice": "Stimme auswählen",
"Toggle Sticky Bottom TTS Bar": "Fixierte TTS-Leiste umschalten",
"Display what I'm reading on Discord": "Zeige was ich auf Discord lese",
"Show on Discord": "Auf Discord zeigen",
"Instant {{action}}": "Sofort {{action}}",
"Instant {{action}} Disabled": "Sofort {{action}} deaktiviert",
"Annotation": "Anmerkung",
"Reset Template": "Vorlage zurücksetzen",
"Annotation style": "Anmerkungsstil",
"Annotation color": "Anmerkungsfarbe",
"Annotation time": "Anmerkungszeit",
"AI": "KI",
"Are you sure you want to re-index this book?": "Möchten Sie dieses Buch wirklich neu indizieren?",
"Enable AI in Settings": "KI in den Einstellungen aktivieren",
"Index This Book": "Dieses Buch indizieren",
"Enable AI search and chat for this book": "KI-Suche und Chat für dieses Buch aktivieren",
"Start Indexing": "Indizierung starten",
"Indexing book...": "Buch wird indiziert...",
"Preparing...": "Vorbereitung...",
"Delete this conversation?": "Diese Unterhaltung löschen?",
"No conversations yet": "Noch keine Unterhaltungen",
"Start a new chat to ask questions about this book": "Starten Sie einen neuen Chat, um Fragen zu diesem Buch zu stellen",
"Rename": "Umbenennen",
"New Chat": "Neuer Chat",
"Chat": "Chat",
"Please enter a model ID": "Bitte geben Sie eine Modell-ID ein",
"Model not available or invalid": "Modell nicht verfügbar oder ungültig",
"Failed to validate model": "Modellvalidierung fehlgeschlagen",
"Couldn't connect to Ollama. Is it running?": "Verbindung zu Ollama fehlgeschlagen. Läuft es?",
"Invalid API key or connection failed": "Ungültiger API-Schlüssel oder Verbindung fehlgeschlagen",
"Connection failed": "Verbindung fehlgeschlagen",
"AI Assistant": "KI-Assistent",
"Enable AI Assistant": "KI-Assistent aktivieren",
"Provider": "Anbieter",
"Ollama (Local)": "Ollama (Lokal)",
"AI Gateway (Cloud)": "KI-Gateway (Cloud)",
"Ollama Configuration": "Ollama-Konfiguration",
"Refresh Models": "Modelle aktualisieren",
"AI Model": "KI-Modell",
"No models detected": "Keine Modelle erkannt",
"AI Gateway Configuration": "KI-Gateway-Konfiguration",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Wählen Sie aus einer Auswahl hochwertiger, wirtschaftlicher KI-Modelle. Sie können auch Ihr eigenes Modell verwenden, indem Sie unten \"Benutzerdefiniertes Modell\" auswählen.",
"API Key": "API-Schlüssel",
"Get Key": "Schlüssel erhalten",
"Model": "Modell",
"Custom Model...": "Benutzerdefiniertes Modell...",
"Custom Model ID": "Benutzerdefinierte Modell-ID",
"Validate": "Validieren",
"Model available": "Modell verfügbar",
"Connection": "Verbindung",
"Test Connection": "Verbindung testen",
"Connected": "Verbunden",
"Custom Colors": "Benutzerdefinierte Farben",
"Color E-Ink Mode": "Farb-E-Ink-Modus",
"Reading Ruler": "Lese-Lineal",
"Enable Reading Ruler": "Lese-Lineal aktivieren",
"Lines to Highlight": "Hervorzuhebende Zeilen",
"Ruler Color": "Linealfarbe",
"Command Palette": "Befehlspalette",
"Search settings and actions...": "Einstellungen und Aktionen suchen...",
"No results found for": "Keine Ergebnisse gefunden für",
"Type to search settings and actions": "Tippen, um Einstellungen und Aktionen zu suchen",
"Recent": "Zuletzt verwendet",
"navigate": "navigieren",
"select": "auswählen",
"close": "schließen",
"Search Settings": "Einstellungen suchen",
"Page Margins": "Seitenränder",
"AI Provider": "KI-Anbieter",
"Ollama URL": "Ollama-URL",
"Ollama Model": "Ollama-Modell",
"AI Gateway Model": "AI Gateway-Modell",
"Actions": "Aktionen",
"Navigation": "Navigation",
"Set status for {{count}} book(s)_one": "Status für {{count}} Buch festlegen",
"Set status for {{count}} book(s)_other": "Status für {{count}} Bücher festlegen",
"Mark as Unread": "Als ungelesen markieren",
"Mark as Finished": "Als beendet markieren",
"Finished": "Beendet",
"Unread": "Ungelesen",
"Clear Status": "Status löschen",
"Status": "Status",
"Loading": "Laden...",
"Exit Paragraph Mode": "Absatzmodus verlassen",
"Paragraph Mode": "Absatzmodus",
"Embedding Model": "Einbettungsmodell",
"{{count}} book(s) synced_one": "{{count}} Buch synchronisiert",
"{{count}} book(s) synced_other": "{{count}} Bücher synchronisiert",
"Unable to start RSVP": "RSVP kann nicht gestartet werden",
"RSVP not supported for PDF": "RSVP wird für PDF nicht unterstützt",
"Select Chapter": "Kapitel auswählen",
"Context": "Kontext",
"Ready": "Bereit",
"Chapter Progress": "Kapitelfortschritt",
"words": "Wörter",
"{{time}} left": "{{time}} übrig",
"Reading progress": "Lesefortschritt",
"Skip back 15 words": "15 Wörter zurück",
"Back 15 words (Shift+Left)": "15 Wörter zurück (Shift+Links)",
"Pause (Space)": "Pause (Leertaste)",
"Play (Space)": "Abspielen (Leertaste)",
"Skip forward 15 words": "15 Wörter vor",
"Forward 15 words (Shift+Right)": "15 Wörter vor (Shift+Rechts)",
"Decrease speed": "Geschwindigkeit verringern",
"Slower (Left/Down)": "Langsamer (Links/Unten)",
"Increase speed": "Geschwindigkeit erhöhen",
"Faster (Right/Up)": "Schneller (Rechts/Oben)",
"Start RSVP Reading": "RSVP-Lesen starten",
"Choose where to start reading": "Wählen Sie, wo das Lesen beginnen soll",
"From Chapter Start": "Vom Kapitelanfang",
"Start reading from the beginning of the chapter": "Ab dem Anfang des Kapitels lesen",
"Resume": "Fortsetzen",
"Continue from where you left off": "Dort fortfahren, wo Sie aufgehört haben",
"From Current Page": "Von der aktuellen Seite",
"Start from where you are currently reading": "Dort beginnen, wo Sie gerade lesen",
"From Selection": "Von der Auswahl",
"Speed Reading Mode": "Schnelllesemodus",
"Scroll left": "Nach links scrollen",
"Scroll right": "Nach rechts scrollen",
"Library Sync Progress": "Bibliotheks-Synchronisierungsfortschritt",
"Back to library": "Zurück zur Bibliothek",
"Group by...": "Gruppieren nach...",
"Export as Plain Text": "Als reinen Text exportieren",
"Export as Markdown": "Als Markdown exportieren",
"Show Page Navigation Buttons": "Navigationsschaltflächen",
"Page {{number}}": "Seite {{number}}",
"highlight": "Hervorhebung",
"underline": "Unterstreichung",
"squiggly": "geschlängelt",
"red": "rot",
"violet": "violett",
"blue": "blau",
"green": "grün",
"yellow": "gelb",
"Select {{style}} style": "Stil {{style}} auswählen",
"Select {{color}} color": "Farbe {{color}} auswählen",
"Close Book": "Buch schließen",
"Speed Reading": "Schnelllesen",
"Close Speed Reading": "Schnelllesen schließen",
"Authors": "Autoren",
"Books": "Bücher",
"Groups": "Gruppen",
"Back to TTS Location": "Zurück zur TTS-Position",
"Metadata": "Metadaten",
"Image viewer": "Bildbetrachter",
"Previous Image": "Vorheriges Bild",
"Next Image": "Nächstes Bild",
"Zoomed": "Gezoomt",
"Zoom level": "Zoomstufe",
"Table viewer": "Tabellenbetrachter",
"Unable to connect to Readwise. Please check your network connection.": "Verbindung zu Readwise nicht möglich. Bitte überprüfen Sie Ihre Netzwerkverbindung.",
"Invalid Readwise access token": "Ungültiges Readwise-Zugriffstoken",
"Disconnected from Readwise": "Von Readwise getrennt",
"Never": "Nie",
"Readwise Settings": "Readwise-Einstellungen",
"Connected to Readwise": "Mit Readwise verbunden",
"Last synced: {{time}}": "Zuletzt synchronisiert: {{time}}",
"Sync Enabled": "Synchronisierung aktiviert",
"Disconnect": "Trennen",
"Connect your Readwise account to sync highlights.": "Verbinden Sie Ihr Readwise-Konto, um Highlights zu synchronisieren.",
"Get your access token at": "Holen Sie sich Ihr Zugriffstoken unter",
"Access Token": "Zugriffstoken",
"Paste your Readwise access token": "Fügen Sie Ihr Readwise-Zugriffstoken ein",
"Config": "Konfiguration",
"Readwise Sync": "Readwise-Synchronisierung",
"Push Highlights": "Highlights übertragen",
"Highlights synced to Readwise": "Highlights mit Readwise synchronisiert",
"Readwise sync failed: no internet connection": "Readwise-Synchronisierung fehlgeschlagen: Keine Internetverbindung",
"Readwise sync failed: {{error}}": "Readwise-Synchronisierung fehlgeschlagen: {{error}}",
"System Screen Brightness": "System-Bildschirmhelligkeit",
"Page:": "Seite:",
"Page: {{number}}": "Seite: {{number}}",
"Annotation page number": "Seitenzahl der Anmerkung",
"Translating...": "Übersetzen...",
"Show Battery Percentage": "Akkustand in Prozent anzeigen",
"Hide Scrollbar": "Scrollleiste ausblenden",
"Skip to last reading position": "Zur letzten Leseposition springen",
"Show context": "Kontext anzeigen",
"Hide context": "Kontext ausblenden",
"Decrease font size": "Schriftgröße verkleinern",
"Increase font size": "Schriftgröße vergrößern",
"Focus": "Fokus",
"Theme color": "Themenfarbe",
"Import failed": "Import fehlgeschlagen",
"Available Formatters:": "Verfügbare Formatierer:",
"Format date": "Datum formatieren",
"Markdown block quote (> per line)": "Markdown-Blockzitat (> pro Zeile)",
"Newlines to <br>": "Zeilenumbrüche zu <br>",
"Change case": "Groß-/Kleinschreibung ändern",
"Trim whitespace": "Leerzeichen entfernen",
"Truncate to n characters": "Auf n Zeichen kürzen",
"Replace text": "Text ersetzen",
"Fallback value": "Ersatzwert",
"Get length": "Länge ermitteln",
"First/last element": "Erstes/letztes Element",
"Join array": "Array verbinden",
"Backup failed: {{error}}": "Sicherung fehlgeschlagen: {{error}}",
"Select Backup": "Sicherung auswählen",
"Restore failed: {{error}}": "Wiederherstellung fehlgeschlagen: {{error}}",
"Backup & Restore": "Sichern & Wiederherstellen",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "Erstellen Sie eine Sicherung Ihrer Bibliothek oder stellen Sie eine frühere Sicherung wieder her. Die Wiederherstellung wird mit Ihrer aktuellen Bibliothek zusammengeführt.",
"Backup Library": "Bibliothek sichern",
"Restore Library": "Bibliothek wiederherstellen",
"Creating backup...": "Sicherung wird erstellt...",
"Restoring library...": "Bibliothek wird wiederhergestellt...",
"{{current}} of {{total}} items": "{{current}} von {{total}} Elementen",
"Backup completed successfully!": "Sicherung erfolgreich abgeschlossen!",
"Restore completed successfully!": "Wiederherstellung erfolgreich abgeschlossen!",
"Your library has been saved to the selected location.": "Ihre Bibliothek wurde am ausgewählten Ort gespeichert.",
"{{added}} books added, {{updated}} books updated.": "{{added}} Bücher hinzugefügt, {{updated}} Bücher aktualisiert.",
"Operation failed": "Vorgang fehlgeschlagen",
"Loading library...": "Bibliothek wird geladen...",
"{{count}} books refreshed_one": "{{count}} Buch aktualisiert",
"{{count}} books refreshed_other": "{{count}} Bücher aktualisiert",
"Failed to refresh metadata": "Metadaten-Aktualisierung fehlgeschlagen",
"Refresh Metadata": "Metadaten aktualisieren",
"Keyboard Shortcuts": "Tastaturkürzel",
"View all keyboard shortcuts": "Alle Tastaturkürzel anzeigen",
"Switch Sidebar Tab": "Seitenleisten-Tab wechseln",
"Toggle Notebook": "Notizbuch ein-/ausblenden",
"Search in Book": "Im Buch suchen",
"Toggle Scroll Mode": "Scrollmodus umschalten",
"Toggle Select Mode": "Auswahlmodus umschalten",
"Toggle Bookmark": "Lesezeichen umschalten",
"Toggle Text to Speech": "Sprachausgabe umschalten",
"Play / Pause TTS": "Sprachausgabe abspielen / pausieren",
"Toggle Paragraph Mode": "Absatzmodus umschalten",
"Highlight Selection": "Auswahl hervorheben",
"Underline Selection": "Auswahl unterstreichen",
"Annotate Selection": "Auswahl kommentieren",
"Search Selection": "Auswahl suchen",
"Copy Selection": "Auswahl kopieren",
"Translate Selection": "Auswahl übersetzen",
"Dictionary Lookup": "Im Wörterbuch nachschlagen",
"Wikipedia Lookup": "In Wikipedia nachschlagen",
"Read Aloud Selection": "Auswahl vorlesen",
"Proofread Selection": "Auswahl korrekturlesen",
"Open Settings": "Einstellungen öffnen",
"Open Command Palette": "Befehlspalette öffnen",
"Show Keyboard Shortcuts": "Tastaturkürzel anzeigen",
"Open Books": "Bücher öffnen",
"Toggle Fullscreen": "Vollbild umschalten",
"Close Window": "Fenster schließen",
"Quit App": "App beenden",
"Go Left / Previous Page": "Nach links / Vorherige Seite",
"Go Right / Next Page": "Nach rechts / Nächste Seite",
"Go Up": "Nach oben",
"Go Down": "Nach unten",
"Previous Chapter": "Vorheriges Kapitel",
"Next Chapter": "Nächstes Kapitel",
"Scroll Half Page Down": "Halbe Seite nach unten scrollen",
"Scroll Half Page Up": "Halbe Seite nach oben scrollen",
"Save Note": "Notiz speichern",
"Single Section Scroll": "Einzelabschnitt-Scrollen",
"General": "Allgemein",
"Text to Speech": "Sprachausgabe",
"Zoom": "Zoom",
"Window": "Fenster",
"Your Bookshelf": "Dein Bücherregal",
"TTS": "Sprachausgabe",
"Media Info": "Medieninfo",
"Update Frequency": "Aktualisierungshäufigkeit",
"Every Sentence": "Jeden Satz",
"Every Paragraph": "Jeden Absatz",
"Every Chapter": "Jedes Kapitel",
"TTS Media Info Update Frequency": "TTS-Medieninfo-Aktualisierungshäufigkeit",
"Select reading speed": "Lesegeschwindigkeit wählen",
"Drag to seek": "Ziehen zum Suchen",
"Punctuation Delay": "Satzzeichen-Verzögerung",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "Bitte bestätigen Sie, dass diese OPDS-Verbindung über Readest-Server in der Web-App weitergeleitet wird, bevor Sie fortfahren.",
"Custom Headers": "Benutzerdefinierte Header",
"Custom Headers (optional)": "Benutzerdefinierte Header (optional)",
"Add one header per line using \"Header-Name: value\".": "Fügen Sie pro Zeile einen Header im Format \"Header-Name: value\" hinzu.",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "Ich verstehe, dass diese OPDS-Verbindung über Readest-Server in der Web-App weitergeleitet wird. Wenn ich Readest meine Anmeldedaten oder Header nicht anvertraue, sollte ich stattdessen die native App verwenden.",
"Unable to connect to Hardcover. Please check your network connection.": "Verbindung zu Hardcover nicht möglich. Bitte überprüfen Sie Ihre Netzwerkverbindung.",
"Invalid Hardcover API token": "Ungültiges Hardcover-API-Token",
"Disconnected from Hardcover": "Von Hardcover getrennt",
"Hardcover Settings": "Hardcover-Einstellungen",
"Connected to Hardcover": "Mit Hardcover verbunden",
"Connect your Hardcover account to sync reading progress and notes.": "Verbinden Sie Ihr Hardcover-Konto, um Lesefortschritt und Notizen zu synchronisieren.",
"Get your API token from hardcover.app → Settings → API.": "Holen Sie Ihr API-Token von hardcover.app → Einstellungen → API.",
"API Token": "API-Token",
"Paste your Hardcover API token": "Fügen Sie Ihr Hardcover-API-Token ein",
"Hardcover sync enabled for this book": "Hardcover-Synchronisierung für dieses Buch aktiviert",
"Hardcover sync disabled for this book": "Hardcover-Synchronisierung für dieses Buch deaktiviert",
"Hardcover Sync": "Hardcover-Synchronisierung",
"Enable for This Book": "Für dieses Buch aktivieren",
"Push Notes": "Notizen übertragen",
"Enable Hardcover sync for this book first.": "Aktivieren Sie zuerst die Hardcover-Synchronisierung für dieses Buch.",
"No annotations or excerpts to sync for this book.": "Keine Anmerkungen oder Auszüge zum Synchronisieren für dieses Buch.",
"Configure Hardcover in Settings first.": "Konfigurieren Sie zuerst Hardcover in den Einstellungen.",
"No new Hardcover note changes to sync.": "Keine neuen Hardcover-Notizänderungen zum Synchronisieren.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover synchronisiert: {{inserted}} neu, {{updated}} aktualisiert, {{skipped}} unverändert",
"Hardcover notes sync failed: {{error}}": "Hardcover-Notizsynchronisierung fehlgeschlagen: {{error}}",
"Reading progress synced to Hardcover": "Lesefortschritt mit Hardcover synchronisiert",
"Hardcover progress sync failed: {{error}}": "Hardcover-Fortschrittssynchronisierung fehlgeschlagen: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "Vorhandene Quellkennung beibehalten",
"Toggle Toolbar": "Symbolleiste umschalten"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Αυτόματη λειτουργία",
"Behavior": "Συμπεριφορά",
"Book": "Βιβλίο",
"Book Cover": "Εξώφυλλο βιβλίου",
"Bookmark": "Σελιδοδείκτης",
"Cancel": "Ακύρωση",
"Chapter": "Κεφάλαιο",
@@ -46,7 +45,6 @@
"Horizontal Direction": "Οριζόντια κατεύθυνση",
"Hyphenation": "Συλλαβισμός",
"Import Books": "Εισαγωγή βιβλίων",
"Language:": "Γλώσσα:",
"Layout": "Διάταξη",
"Light Mode": "Φωτεινή λειτουργία",
"Loading...": "Φόρτωση...",
@@ -68,8 +66,8 @@
"Paging Animation": "Κινούμενα σχέδια σελιδοποίησης",
"Paragraph": "Παράγραφος",
"Parallel Read": "Παράλληλη ανάγνωση",
"Published:": "Δημοσιεύτηκε:",
"Publisher:": "Εκδότης:",
"Published": "Δημοσιεύτηκε",
"Publisher": "Εκδότης",
"Reading Progress Synced": "Ο συγχρονισμός προόδου ανάγνωσης ολοκληρώθηκε",
"Reload Page": "Επαναφόρτωση σελίδας",
"Reveal in File Explorer": "Εμφάνιση στον εξερευνητή αρχείων",
@@ -83,7 +81,6 @@
"Search...": "Αναζήτηση...",
"Select Book": "Επιλογή βιβλίου",
"Select Books": "Επιλογή βιβλίων",
"Select Multiple Books": "Επιλογή πολλαπλών βιβλίων",
"Sepia": "Σέπια",
"Serif Font": "Γραμματοσειρά Serif",
"Show Book Details": "Εμφάνιση λεπτομερειών βιβλίου",
@@ -94,23 +91,21 @@
"Slow": "Αργά",
"Solarized": "Solarized",
"Speak": "Ομιλία",
"Subjects:": "Θέματα:",
"Subjects": "Θέματα",
"System Fonts": "Γραμματοσειρές συστήματος",
"TTS not supported in this device": "Η μετατροπή κειμένου σε ομιλία δεν υποστηρίζεται σε αυτή τη συσκευή",
"Theme Color": "Χρώμα θέματος",
"Theme Mode": "Λειτουργία θέματος",
"Translate": "Μετάφραση",
"Translated Text": "Μεταφρασμένο κείμενο",
"Unknown": "Άγνωστο",
"Untitled": "Χωρίς τίτλο",
"Updated:": "Ενημερώθηκε:",
"Updated": "Ενημερώθηκε",
"Version {{version}}": "Έκδοση {{version}}",
"Vertical Direction": "Κάθετη κατεύθυνση",
"Welcome to your library. You can import your books here and read them anytime.": "Καλώς ήρθατε στη βιβλιοθήκη σας. Μπορείτε να εισάγετε τα βιβλία σας εδώ και να τα διαβάσετε οποιαδήποτε στιγμή.",
"Wikipedia": "Βικιπαίδεια",
"Writing Mode": "Λειτουργία γραφής",
"Your Library": "Η βιβλιοθήκη σας",
"TTS not supported for PDF": "Η μετατροπή κειμένου σε ομιλία δεν υποστηρίζεται για αρχεία PDF",
"Override Book Font": "Παράκαμψη γραμματοσειράς βιβλίου",
"Apply to All Books": "Εφαρμογή σε όλα τα βιβλία",
"Apply to This Book": "Εφαρμογή σε αυτό το βιβλίο",
@@ -120,6 +115,7 @@
"Book Details": "Λεπτομέρειες βιβλίου",
"From Local File": "Από τοπικό αρχείο",
"TOC": "Πίνακας περιεχομένων",
"Table of Contents": "Πίνακας περιεχομένων",
"Book uploaded: {{title}}": "Το βιβλίο με τίτλο {{title}} ανέβηκε",
"Failed to upload book: {{title}}": "Αποτυχία ανέβασμα βιβλίου: {{title}}",
"Book downloaded: {{title}}": "Το βιβλίο με τίτλο {{title}} κατέβηκε",
@@ -176,9 +172,6 @@
"Token": "Κωδικός επαλήθευσης",
"Your OTP token": "Ο κωδικός OTP σας",
"Verify token": "Επαλήθευση κωδικού",
"Sign in with Google": "Σύνδεση με Google",
"Sign in with Apple": "Σύνδεση με Apple",
"Sign in with GitHub": "Σύνδεση με GitHub",
"Account": "Λογαριασμός",
"Failed to delete user. Please try again later.": "Αποτυχία διαγραφής χρήστη. Παρακαλώ δοκιμάστε ξανά αργότερα.",
"Community Support": "Υποστήριξη κοινότητας",
@@ -191,12 +184,11 @@
"RTL Direction": "Κατεύθυνση RTL",
"Maximum Column Height": "Μέγιστο ύψος στήλης",
"Maximum Column Width": "Μέγιστο πλάτος στήλης",
"Continuous Scroll": "Συνεχής κύλιση",
"Fullscreen": "Πλήρης οθόνη",
"No supported files found. Supported formats: {{formats}}": "Δεν βρέθηκαν υποστηριζόμενα αρχεία. Υποστηριζόμενες μορφές: {{formats}}",
"Drop to Import Books": "Ρίξτε για εισαγωγή βιβλίων",
"Custom": "Προσαρμοσμένο",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Όλος ο κόσμος είναι σκηνή,\nΚαι όλοι οι άνδρες και οι γυναίκες απλώς ηθοποιοί·\nΈχουν τις εξόδους και τις εισόδους τους,\nΚαι ένας άνθρωπος στον χρόνο του παίζει πολλούς ρόλους,\nΟι πράξεις του υπάρχουν σε επτά ηλικίες.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Όλος ο κόσμος είναι σκηνή,\nΚαι όλοι οι άνδρες και οι γυναίκες απλώς ηθοποιοί·\nΈχουν τις εξόδους και τις εισόδους τους,\nΚαι ένας άνθρωπος στον χρόνο του παίζει πολλούς ρόλους,\nΟι πράξεις του υπάρχουν σε επτά ηλικίες.\n\n— William Shakespeare",
"Custom Theme": "Προσαρμοσμένο θέμα",
"Theme Name": "Όνομα θέματος",
"Text Color": "Χρώμα κειμένου",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "Αυτόματη εισαγωγή κατά το άνοιγμα αρχείου",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "Δεν εντοπίστηκαν κεφάλαια.",
"Failed to parse the EPUB file.": "Αποτυχία ανάλυσης του αρχείου EPUB.",
"This book format is not supported.": "Αυτή η μορφή βιβλίου δεν υποστηρίζεται.",
"No chapters detected": "Δεν εντοπίστηκαν κεφάλαια",
"Failed to parse the EPUB file": "Αποτυχία ανάλυσης του αρχείου EPUB",
"This book format is not supported": "Αυτή η μορφή βιβλίου δεν υποστηρίζεται",
"Unable to fetch the translation. Please log in first and try again.": "Αδυναμία λήψης της μετάφρασης. Παρακαλώ συνδεθείτε πρώτα και δοκιμάστε ξανά.",
"Group": "Ομάδα",
"Always on Top": "Πάντα στην κορυφή",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "Κατεβάζω {{downloaded}} από {{contentLength}}",
"Download finished": "Η λήψη ολοκληρώθηκε",
"DOWNLOAD & INSTALL": "ΛΗΨΗ & ΕΓΚΑΤΑΣΤΑΣΗ",
"Changelog:": "Αλλαγές:",
"Changelog": "Αλλαγές",
"Software Update": "Ενημέρωση λογισμικού",
"Title": "Τίτλος",
"Date Read": "Ημερομηνία ανάγνωσης",
@@ -253,18 +245,15 @@
"Ascending": "Αύξουσα",
"Descending": "Φθίνουσα",
"Sort by...": "Ταξινόμηση κατά...",
"Added:": "Προστέθηκε:",
"Format:": "Μορφή:",
"Added": "Προστέθηκε",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "Περιγραφή:",
"Description": "Περιγραφή",
"No description available": "Δεν είναι διαθέσιμη καμία περιγραφή",
"List": "Λίστα",
"Grid": "Πλέγμα",
"(from 'As You Like It', Act II)": "('Όπως σας αρέσει', Πράξη II)",
"Link Color": "Χρώμα συνδέσμου",
"Volume Keys for Page Flip": "Ανατροπή με πλήκτρα έντασης",
"Clicks for Page Flip": "Κλικ για ανατροπή σελίδας",
"Swap Clicks Area": "Ανταλλαγή περιοχής κλικ",
"Screen": "Οθόνη",
"Orientation": "Προσανατολισμός",
"Portrait": "Πορτραίτο",
@@ -273,7 +262,7 @@
"Checking for updates...": "Έλεγχος για ενημερώσεις...",
"Error checking for updates": "Σφάλμα κατά τον έλεγχο για ενημερώσεις",
"Details": "Πληρ.",
"File Size:": "Μέγεθος αρχείου:",
"File Size": "Μέγεθος αρχείου",
"Auto Detect": "Αυτόματη ανίχνευση",
"Next Section": "Επόμενη ενότητα",
"Previous Section": "Προηγούμενη ενότητα",
@@ -300,7 +289,6 @@
"Disable Translation": "Απενεργοποίηση μετάφρασης",
"Scroll": "Κύλιση",
"Overlap Pixels": "Επικάλυψη εικονοστοιχείων",
"Click": "Κλικ",
"System Language": "Γλώσσα συστήματος",
"Security": "Ασφάλεια",
"Allow JavaScript": "Επιτρέψτε JavaScript",
@@ -314,7 +302,6 @@
"Synced at {{time}}": "Συγχρονίστηκε στις {{time}}",
"Never synced": "Ποτέ δεν συγχρονίστηκε",
"Show Remaining Time": "Εμφάνιση υπολειπόμενου χρόνου",
"Show Page Number": "Εμφάνιση αριθμού σελίδας",
"{{time}} min left in chapter": "{{time}} λεπτά απομένουν στο κεφάλαιο",
"Override Book Color": "Παράκαμψη χρώματος βιβλίου",
"Login Required": "Απαιτείται σύνδεση",
@@ -337,7 +324,6 @@
"Left Margin (px)": "Αριστερό περιθώριο (px)",
"Column Gap (%)": "Απόσταση στηλών (%)",
"Always Show Status Bar": "Πάντα εμφάνιση γραμμής κατάστασης",
"Translation Not Available": "Η μετάφραση δεν είναι διαθέσιμη",
"Custom Content CSS": "Προσαρμοσμένο CSS περιεχομένου",
"Enter CSS for book content styling...": "Εισαγάγετε CSS για στυλ περιεχομένου βιβλίου...",
"Custom Reader UI CSS": "Προσαρμοσμένο CSS διεπαφής αναγνώστη",
@@ -347,11 +333,11 @@
"Fit": "Προσαρμογή",
"Reset {{settings}}": "Επαναφορά {{settings}}",
"Reset Settings": "Επαναφορά ρυθμίσεων",
"{{count}} pages left in chapter_one": "Μένει {{count}} σελίδα",
"{{count}} pages left in chapter_other": "Μένουν {{count}} σελίδες",
"{{count}} pages left in chapter_one": "<1>Μένει </1><0>{{count}}</0><1> σελίδα</1>",
"{{count}} pages left in chapter_other": "<1>Μένουν </1><0>{{count}}</0><1> σελίδες</1>",
"Show Remaining Pages": "Εμφάνιση υπολοίπων",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Διαχείριση συνδρομής",
"Coming Soon": "Έρχεται σύντομα",
@@ -359,7 +345,6 @@
"Upgrade to Plus or Pro": "Αναβάθμιση σε Plus ή Pro",
"Current Plan": "Τρέχον πρόγραμμα",
"Plan Limits": "Όρια προγράμματος",
"Failed to manage subscription. Please try again later.": "Αποτυχία διαχείρισης της συνδρομής. Παρακαλώ δοκιμάστε ξανά αργότερα.",
"Processing your payment...": "Επεξεργασία πληρωμής...",
"Please wait while we confirm your subscription.": "Παρακαλώ περιμένετε όσο επιβεβαιώνουμε τη συνδρομή σας.",
"Payment Processing": "Επεξεργασία πληρωμής",
@@ -372,7 +357,6 @@
"Email:": "Email:",
"Plan:": "Πρόγραμμα:",
"Amount:": "Ποσό:",
"Subscription ID:": "ID συνδρομής:",
"Go to Library": "Μετάβαση στη βιβλιοθήκη",
"Need help? Contact our support team at support@readest.com": "Χρειάζεστε βοήθεια; Επικοινωνήστε με την υποστήριξη στο support@readest.com",
"Free Plan": "Δωρεάν πρόγραμμα",
@@ -402,7 +386,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "Απεριόριστη μετατροπή κειμένου σε ήχο.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Περισσότερες μεταφράσεις και δυνατότητες.",
"DeepL Pro Access": "Πρόσβαση στο DeepL Pro",
"2 GB Cloud Sync Storage": "2 GB αποθήκευση στο cloud",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Γρήγορη και άμεση υποστήριξη.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Έχετε φτάσει το ημερήσιο όριο. Κάντε αναβάθμιση για περισσότερες μεταφράσεις.",
"Includes All Plus Plan Benefits": "Περιλαμβάνει Όλα τα Οφέλη του Plus Πλάνου",
@@ -412,10 +395,793 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Αξιοποιήστε ισχυρά εργαλεία AI για εξυπνότερη ανάγνωση, μετάφραση και ανακάλυψη περιεχομένου.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Μεταφράστε έως 100.000 χαρακτήρες ημερησίως με τη πιο ακριβή μηχανή μετάφρασης.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Μεταφράστε έως 500.000 χαρακτήρες ημερησίως με τη πιο ακριβή μηχανή μετάφρασης.",
"10 GB Cloud Sync Storage": "10 GB Αποθήκευση Cloud Sync",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "Αποθηκεύστε και αποκτήστε πρόσβαση στη συλλογή ανάγνωσης με έως 2 GB ασφαλή cloud αποθήκευση.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "Αποθηκεύστε και αποκτήστε πρόσβαση στη συλλογή ανάγνωσης με έως 10 GB ασφαλή cloud αποθήκευση.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Αποθηκεύστε και αποκτήστε πρόσβαση στη συλλογή ανάγνωσης με έως 5 GB ασφαλή cloud αποθήκευση.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Αποθηκεύστε και αποκτήστε πρόσβαση στη συλλογή ανάγνωσης με έως 20 GB ασφαλή cloud αποθήκευση.",
"Deleted cloud backup of the book: {{title}}": "Διαγράφηκε το αντίγραφο ασφαλείας του βιβλίου: {{title}}",
"Failed to delete cloud backup of the book": "Αποτυχία διαγραφής του αντιγράφου ασφαλείας του βιβλίου",
"Are you sure to delete the cloud backup of the selected book?": "Είστε σίγουροι ότι θέλετε να διαγράψετε το αντίγραφο ασφαλείας του επιλεγμένου βιβλίου;"
"Are you sure to delete the cloud backup of the selected book?": "Είστε σίγουροι ότι θέλετε να διαγράψετε το αντίγραφο ασφαλείας του επιλεγμένου βιβλίου;",
"What's New in Readest": "Τι νέο υπάρχει στο Readest",
"Enter book title": "Εισάγετε τίτλο βιβλίου",
"Subtitle": "Υπότιτλος",
"Enter book subtitle": "Εισάγετε υπότιτλο βιβλίου",
"Enter author name": "Εισάγετε όνομα συγγραφέα",
"Series": "Σειρά",
"Enter series name": "Εισάγετε όνομα σειράς",
"Series Index": "Αριθμός σειράς",
"Enter series index": "Εισάγετε αριθμό σειράς",
"Total in Series": "Σύνολο στη σειρά",
"Enter total books in series": "Εισάγετε συνολικό αριθμό βιβλίων στη σειρά",
"Enter publisher": "Εισάγετε εκδότη",
"Publication Date": "Ημερομηνία έκδοσης",
"Identifier": "Αναγνωριστικό",
"Enter book description": "Εισάγετε περιγραφή βιβλίου",
"Change cover image": "Αλλαγή εικόνας εξωφύλλου",
"Replace": "Αντικατάσταση",
"Unlock cover": "Ξεκλείδωμα εξωφύλλου",
"Lock cover": "Κλείδωμα εξωφύλλου",
"Auto-Retrieve Metadata": "Αυτόματη ανάκτηση μεταδεδομένων",
"Auto-Retrieve": "Αυτόματη ανάκτηση",
"Unlock all fields": "Ξεκλείδωμα όλων των πεδίων",
"Unlock All": "Ξεκλείδωμα όλων",
"Lock all fields": "Κλείδωμα όλων των πεδίων",
"Lock All": "Κλείδωμα όλων",
"Reset": "Επαναφορά",
"Edit Metadata": "Επεξεργασία μεταδεδομένων",
"Locked": "Κλειδωμένο",
"Select Metadata Source": "Επιλέξτε πηγή μεταδεδομένων",
"Keep manual input": "Διατήρηση χειροκίνητης εισαγωγής",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Μυθοπλασία, Επιστήμη, Ιστορία",
"Open Book in New Window": "Άνοιγμα βιβλίου σε νέο παράθυρο",
"Voices for {{lang}}": "Φωνές για {{lang}}",
"Yandex Translate": "Μετάφραση Yandex",
"YYYY or YYYY-MM-DD": "YYYY ή YYYY-MM-DD",
"Restore Purchase": "Επαναφορά αγοράς",
"No purchases found to restore.": "Δεν βρέθηκαν αγορές για επαναφορά.",
"Failed to restore purchases.": "Αποτυχία επαναφοράς αγορών.",
"Failed to manage subscription.": "Αποτυχία διαχείρισης συνδρομής.",
"Failed to load subscription plans.": "Αποτυχία φόρτωσης σχεδίων συνδρομής.",
"year": "έτος",
"Failed to create checkout session": "Αποτυχία δημιουργίας συνεδρίας πληρωμής",
"Storage": "Αποθήκευση",
"Terms of Service": "Όροι χρήσης",
"Privacy Policy": "Πολιτική απορρήτου",
"Disable Double Click": "Απενεργοποίηση διπλού κλικ",
"TTS not supported for this document": "Η τεχνολογία TTS δεν υποστηρίζεται για αυτό το έγγραφο.",
"Reset Password": "Επαναφορά κωδικού",
"Show Reading Progress": "Εμφάνιση προόδου ανάγνωσης",
"Reading Progress Style": "Στυλ προόδου ανάγνωσης",
"Page Number": "Αριθμός σελίδας",
"Percentage": "Ποσοστό",
"Deleted local copy of the book: {{title}}": "Διαγράφηκε το τοπικό αντίγραφο του βιβλίου: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Αποτυχία διαγραφής του αντιγράφου ασφαλείας του βιβλίου: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Αποτυχία διαγραφής της τοπικής αντιγράφου του βιβλίου: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Είστε σίγουροι ότι θέλετε να διαγράψετε την τοπική αντιγραφή του επιλεγμένου βιβλίου;",
"Remove from Cloud & Device": "Αφαίρεση από το Cloud & Device",
"Remove from Cloud Only": "Αφαίρεση μόνο από το Cloud",
"Remove from Device Only": "Αφαίρεση μόνο από το Device",
"Disconnected": "Αποσυνδεδεμένο",
"KOReader Sync Settings": "Ρυθμίσεις συγχρονισμού KOReader",
"Sync Strategy": "Στρατηγική συγχρονισμού",
"Ask on conflict": "Ρώτησε σε περίπτωση σύγκρουσης",
"Always use latest": "Χρησιμοποίησε πάντα την τελευταία έκδοση",
"Send changes only": "Αποστολή μόνο αλλαγών",
"Receive changes only": "Λήψη μόνο αλλαγών",
"Checksum Method": "Μέθοδος ελέγχου",
"File Content (recommended)": "Περιεχόμενο αρχείου (συνιστάται)",
"File Name": "Όνομα αρχείου",
"Device Name": "Όνομα συσκευής",
"Connect to your KOReader Sync server.": "Συνδεθείτε στον διακομιστή συγχρονισμού KOReader.",
"Server URL": "Διεύθυνση URL διακομιστή",
"Username": "Όνομα χρήστη",
"Your Username": "Το όνομα χρήστη σας",
"Password": "Κωδικός πρόσβασης",
"Connect": "Σύνδεση",
"KOReader Sync": "Συγχρονισμός KOReader",
"Sync Conflict": "Σύγκρουση συγχρονισμού",
"Sync reading progress from \"{{deviceName}}\"?": "Συγχρονίστε την πρόοδο ανάγνωσης από το \"{{deviceName}}\";",
"another device": "άλλη συσκευή",
"Local Progress": "Τοπική πρόοδος",
"Remote Progress": "Απομακρυσμένη πρόοδος",
"Page {{page}} of {{total}} ({{percentage}}%)": "Σελίδα {{page}} από {{total}} ({{percentage}}%)",
"Current position": "Τρέχουσα θέση",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Περίπου σελίδα {{page}} από {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Περίπου {{percentage}}%",
"Failed to connect": "Αποτυχία σύνδεσης",
"Sync Server Connected": "Ο διακομιστής συγχρονισμού είναι συνδεδεμένος",
"Sync as {{userDisplayName}}": "Συγχρονισμός ως {{userDisplayName}}",
"Custom Fonts": "Προσαρμοσμένες Γραμματοσειρές",
"Cancel Delete": "Ακύρωση Διαγραφής",
"Import Font": "Εισαγωγή Γραμματοσειράς",
"Delete Font": "Διαγραφή Γραμματοσειράς",
"Tips": "Συμβουλές",
"Custom fonts can be selected from the Font Face menu": "Οι προσαρμοσμένες γραμματοσειρές μπορούν να επιλεγούν από το μενού Γραμματοσειράς",
"Manage Custom Fonts": "Διαχείριση Προσαρμοσμένων Γραμματοσειρών",
"Select Files": "Επιλογή Αρχείων",
"Select Image": "Επιλογή Εικόνας",
"Select Video": "Επιλογή Βίντεο",
"Select Audio": "Επιλογή Ήχου",
"Select Fonts": "Επιλογή Γραμματοσειρών",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Υποστηριζόμενες μορφές γραμματοσειρών: .ttf, .otf, .woff, .woff2",
"Push Progress": "Αποστολή προόδου",
"Pull Progress": "Λήψη προόδου",
"Previous Paragraph": "Προηγούμενη παράγραφος",
"Previous Sentence": "Προηγούμενη πρόταση",
"Pause": "Παύση",
"Play": "Αναπαραγωγή",
"Next Sentence": "Επόμενη πρόταση",
"Next Paragraph": "Επόμενη παράγραφος",
"Separate Cover Page": "Ξεχωριστή σελίδα εξωφύλλου",
"Resize Notebook": "Αλλαγή μεγέθους σημειωματάριου",
"Resize Sidebar": "Αλλαγή μεγέθους πλαϊνής γραμμής",
"Get Help from the Readest Community": "Λάβετε βοήθεια από την κοινότητα Readest",
"Remove cover image": "Αφαίρεση εικόνας εξωφύλλου",
"Bookshelf": "Ράφι βιβλίων",
"View Menu": "Προβολή μενού",
"Settings Menu": "Μενού ρυθμίσεων",
"View account details and quota": "Προβολή στοιχείων λογαριασμού και ορίου",
"Library Header": "Κεφαλίδα βιβλιοθήκης",
"Book Content": "Περιεχόμενο βιβλίου",
"Footer Bar": "Γραμμή υποσέλιδου",
"Header Bar": "Γραμμή κεφαλίδας",
"View Options": "Επιλογές προβολής",
"Book Menu": "Μενού βιβλίου",
"Search Options": "Επιλογές αναζήτησης",
"Close": "Κλείσιμο",
"Delete Book Options": "Επιλογές διαγραφής βιβλίου",
"ON": "ΕΝΕΡΓΟΠΟΙΗΣΗ",
"OFF": "ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ",
"Reading Progress": "Πρόοδος ανάγνωσης",
"Page Margin": "Περιθώριο σελίδας",
"Remove Bookmark": "Αφαίρεση σελιδοδείκτη",
"Add Bookmark": "Προσθήκη σελιδοδείκτη",
"Books Content": "Περιεχόμενο βιβλίων",
"Jump to Location": "Μετάβαση σε τοποθεσία",
"Unpin Notebook": "Αποκαθήλωση σημειωματάριου",
"Pin Notebook": "Καθήλωση σημειωματάριου",
"Hide Search Bar": "Απόκρυψη γραμμής αναζήτησης",
"Show Search Bar": "Εμφάνιση γραμμής αναζήτησης",
"On {{current}} of {{total}} page": "Στη σελίδα {{current}} από {{total}}",
"Section Title": "Τίτλος ενότητας",
"Decrease": "Μείωση",
"Increase": "Αύξηση",
"Settings Panels": "Πίνακες ρυθμίσεων",
"Settings": "Ρυθμίσεις",
"Unpin Sidebar": "Αποκαθήλωση πλαϊνής γραμμής",
"Pin Sidebar": "Καθήλωση πλαϊνής γραμμής",
"Toggle Sidebar": "Εναλλαγή πλαϊνής γραμμής",
"Toggle Translation": "Εναλλαγή μετάφρασης",
"Translation Disabled": "Η μετάφραση είναι απενεργοποιημένη",
"Minimize": "Ελαχιστοποίηση",
"Maximize or Restore": "Μεγιστοποίηση ή Επαναφορά",
"Exit Parallel Read": "Έξοδος από την παράλληλη ανάγνωση",
"Enter Parallel Read": "Είσοδος στην παράλληλη ανάγνωση",
"Zoom Level": "Επίπεδο ζουμ",
"Zoom Out": "Μείωση ζουμ",
"Reset Zoom": "Επαναφορά ζουμ",
"Zoom In": "Αύξηση ζουμ",
"Zoom Mode": "Λειτουργία ζουμ",
"Single Page": "Μοναδική σελίδα",
"Auto Spread": "Αυτόματη εξάπλωση",
"Fit Page": "Προσαρμογή σελίδας",
"Fit Width": "Προσαρμογή πλάτους",
"Failed to select directory": "Αποτυχία επιλογής καταλόγου",
"The new data directory must be different from the current one.": "Ο νέος κατάλογος δεδομένων πρέπει να είναι διαφορετικός από τον τρέχοντα.",
"Migration failed: {{error}}": "Η μετανάστευση απέτυχε: {{error}}",
"Change Data Location": "Αλλαγή τοποθεσίας δεδομένων",
"Current Data Location": "Τρέχουσα τοποθεσία δεδομένων",
"Total size: {{size}}": "Συνολικό μέγεθος: {{size}}",
"Calculating file info...": "Υπολογισμός πληροφοριών αρχείου...",
"New Data Location": "Νέα τοποθεσία δεδομένων",
"Choose Different Folder": "Επιλέξτε διαφορετικό φάκελο",
"Choose New Folder": "Επιλέξτε νέο φάκελο",
"Migrating data...": "Μεταφορά δεδομένων...",
"Copying: {{file}}": "Αντιγραφή: {{file}}",
"{{current}} of {{total}} files": "{{current}} από {{total}} αρχεία",
"Migration completed successfully!": "Η μετανάστευση ολοκληρώθηκε με επιτυχία!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Τα δεδομένα σας έχουν μεταφερθεί στη νέα τοποθεσία. Παρακαλώ επανεκκινήστε την εφαρμογή για να ολοκληρώσετε τη διαδικασία.",
"Migration failed": "Η μετανάστευση απέτυχε",
"Important Notice": "Σημαντική ειδοποίηση",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Αυτό θα μεταφέρει όλα τα δεδομένα της εφαρμογής σας στη νέα τοποθεσία. Βεβαιωθείτε ότι ο προορισμός έχει αρκετό ελεύθερο χώρο.",
"Restart App": "Επανεκκίνηση εφαρμογής",
"Start Migration": "Έναρξη μετανάστευσης",
"Advanced Settings": "Προηγμένες ρυθμίσεις",
"File count: {{size}}": "Αριθμός αρχείων: {{size}}",
"Background Read Aloud": "Ανάγνωση στο παρασκήνιο",
"Ready to read aloud": "Έτοιμο για ανάγνωση",
"Read Aloud": "Ανάγνωση",
"Screen Brightness": "Φωτεινότητα οθόνης",
"Background Image": "Εικόνα φόντου",
"Import Image": "Εισαγωγή εικόνας",
"Opacity": "Αδιαφάνεια",
"Size": "Μέγεθος",
"Cover": "Εξώφυλλο",
"Contain": "Περιέχει",
"{{number}} pages left in chapter": "<1>Μένουν </1><0>{{number}}</0><1> σελίδες στο κεφάλαιο</1>",
"Device": "Συσκευή",
"E-Ink Mode": "Λειτουργία E-Ink",
"Highlight Colors": "Χρώματα επισήμανσης",
"Pagination": "Σελιδοποίηση",
"Disable Double Tap": "Απενεργοποίηση διπλού ταπ",
"Tap to Paginate": "Ταπ για σελιδοποίηση",
"Click to Paginate": "Κλικ για σελιδοποίηση",
"Tap Both Sides": "Ταπ και στις δύο πλευρές",
"Click Both Sides": "Κλικ και στις δύο πλευρές",
"Swap Tap Sides": "Ανταλλαγή πλευρών ταπ",
"Swap Click Sides": "Ανταλλαγή πλευρών κλικ",
"Source and Translated": "Πηγή και Μεταφρασμένο",
"Translated Only": "Μόνο Μεταφρασμένο",
"Source Only": "Μόνο πηγή",
"TTS Text": "Κείμενο TTS",
"The book file is corrupted": "Το αρχείο του βιβλίου είναι κατεστραμμένο",
"The book file is empty": "Το αρχείο του βιβλίου είναι κενό",
"Failed to open the book file": "Αποτυχία ανοίγματος του αρχείου βιβλίου",
"On-Demand Purchase": "Αγορά κατόπιν αιτήματος",
"Full Customization": "Πλήρης προσαρμογή",
"Lifetime Plan": "Σχέδιο ζωής",
"One-Time Payment": "Εφάπαξ πληρωμή",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Κάντε μια εφάπαξ πληρωμή για να απολαύσετε διαρκή πρόσβαση σε συγκεκριμένες δυνατότητες σε όλες τις συσκευές. Αγοράστε συγκεκριμένες δυνατότητες ή υπηρεσίες μόνο όταν τις χρειάζεστε.",
"Expand Cloud Sync Storage": "Επέκταση αποθήκευσης συγχρονισμού Cloud",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Επεκτείνετε την αποθήκευση cloud σας για πάντα με μια εφάπαξ αγορά. Κάθε επιπλέον αγορά προσθέτει περισσότερο χώρο.",
"Unlock All Customization Options": "Ξεκλειδώστε όλες τις επιλογές προσαρμογής",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Ξεκλειδώστε επιπλέον θέματα, γραμματοσειρές, επιλογές διάταξης και δυνατότητες ανάγνωσης, μεταφραστές, υπηρεσίες αποθήκευσης cloud.",
"Purchase Successful!": "Η αγορά ήταν επιτυχής!",
"lifetime": "διαρκής",
"Thank you for your purchase! Your payment has been processed successfully.": "Σας ευχαριστούμε για την αγορά σας! Η πληρωμή σας έχει επεξεργαστεί με επιτυχία.",
"Order ID:": "Αριθμός παραγγελίας:",
"TTS Highlighting": "Επισήμανση TTS",
"Style": "Στυλ",
"Underline": "Υπογράμμιση",
"Strikethrough": "Διαγραμμένο",
"Squiggly": "Κυματιστό",
"Outline": "Περίγραμμα",
"Save Current Color": "Αποθήκευση τρέχουσας χρώματος",
"Quick Colors": "Γρήγορα χρώματα",
"Highlighter": "Υπογραμμιστής",
"Save Book Cover": "Αποθήκευση εξωφύλλου βιβλίου",
"Auto-save last book cover": "Αυτόματη αποθήκευση τελευταίου εξωφύλλου βιβλίου",
"Back": "Πίσω",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Το email επιβεβαίωσης στάλθηκε! Παρακαλώ έλεγξε την παλιά και τη νέα σου διεύθυνση email για να επιβεβαιώσεις την αλλαγή.",
"Failed to update email": "Αποτυχία ενημέρωσης email",
"New Email": "Νέο email",
"Your new email": "Το νέο σου email",
"Updating email ...": "Ενημέρωση email ...",
"Update email": "Ενημέρωση email",
"Current email": "Τρέχον email",
"Update Email": "Ενημέρωση email",
"All": "Όλα",
"Unable to open book": "Αδύνατη η άνοιγμα του βιβλίου",
"Punctuation": "Στίξη",
"Replace Quotation Marks": "Αντικατάσταση εισαγωγικών",
"Enabled only in vertical layout.": "Ενεργοποιημένο μόνο σε κάθετη διάταξη.",
"No Conversion": "Χωρίς μετατροπή",
"Simplified to Traditional": "Απλοπ. → Παραδ.",
"Traditional to Simplified": "Παραδ. → Απλοπ.",
"Simplified to Traditional (Taiwan)": "Απλοπ. → Παραδ. (Ταϊβάν)",
"Simplified to Traditional (Hong Kong)": "Απλοπ. → Παραδ. (Χονγκ Κονγκ)",
"Simplified to Traditional (Taiwan), with phrases": "Απλοπ. → Παραδ. (Ταϊβάν • φράσεις)",
"Traditional (Taiwan) to Simplified": "Παραδ. (Ταϊβάν) → Απλοπ.",
"Traditional (Hong Kong) to Simplified": "Παραδ. (Χονγκ Κονγκ) → Απλοπ.",
"Traditional (Taiwan) to Simplified, with phrases": "Παραδ. (Ταϊβάν • φράσεις) → Απλοπ.",
"Convert Simplified and Traditional Chinese": "Μετατροπή Απλοπ./Παραδ. Κινέζικων",
"Convert Mode": "Λειτουργία μετατροπής",
"Failed to auto-save book cover for lock screen: {{error}}": "Αποτυχία αυτόματης αποθήκευσης εξωφύλλου βιβλίου για την οθόνη κλειδώματος: {{error}}",
"Download from Cloud": "Λήψη από το Cloud",
"Upload to Cloud": "Ανέβασμα στο Cloud",
"Clear Custom Fonts": "Καθαρισμός προσαρμοσμένων γραμματοσειρών",
"Columns": "Στήλες",
"OPDS Catalogs": "Κατάλογοι OPDS",
"Adding LAN addresses is not supported in the web app version.": "Η προσθήκη διευθύνσεων LAN δεν υποστηρίζεται στην έκδοση web της εφαρμογής.",
"Invalid OPDS catalog. Please check the URL.": "Μη έγκυρος κατάλογος OPDS. Ελέγξτε το URL.",
"Browse and download books from online catalogs": "Περιηγηθείτε και κατεβάστε βιβλία από online καταλόγους",
"My Catalogs": "Οι Κατάλογοί μου",
"Add Catalog": "Προσθήκη Καταλόγου",
"No catalogs yet": "Δεν υπάρχουν ακόμα κατάλογοι",
"Add your first OPDS catalog to start browsing books": "Προσθέστε τον πρώτο σας κατάλογο OPDS για να αρχίσετε την περιήγηση.",
"Add Your First Catalog": "Προσθήκη Πρώτου Καταλόγου",
"Browse": "Περιήγηση",
"Popular Catalogs": "Δημοφιλείς Κατάλογοι",
"Add": "Προσθήκη",
"Add OPDS Catalog": "Προσθήκη Καταλόγου OPDS",
"Catalog Name": "Όνομα Καταλόγου",
"My Calibre Library": "Η Βιβλιοθήκη μου στο Calibre",
"OPDS URL": "OPDS URL",
"Username (optional)": "Όνομα χρήστη (προαιρετικό)",
"Password (optional)": "Κωδικός πρόσβασης (προαιρετικό)",
"Description (optional)": "Περιγραφή (προαιρετική)",
"A brief description of this catalog": "Μια σύντομη περιγραφή του καταλόγου",
"Validating...": "Γίνεται έλεγχος...",
"View All": "Προβολή όλων",
"Forward": "Μπροστά",
"Home": "Αρχική",
"{{count}} items_one": "{{count}} στοιχείο",
"{{count}} items_other": "{{count}} στοιχεία",
"Download completed": "Η λήψη ολοκληρώθηκε",
"Download failed": "Η λήψη απέτυχε",
"Open Access": "Ανοιχτή πρόσβαση",
"Borrow": "Δανεισμός",
"Buy": "Αγορά",
"Subscribe": "Συνδρομή",
"Sample": "Δείγμα",
"Download": "Λήψη",
"Open & Read": "Άνοιγμα & Ανάγνωση",
"Tags": "Ετικέτες",
"Tag": "Ετικέτα",
"First": "Πρώτο",
"Previous": "Προηγούμενο",
"Next": "Επόμενο",
"Last": "Τελευταίο",
"Cannot Load Page": "Δεν είναι δυνατή η φόρτωση της σελίδας",
"An error occurred": "Προέκυψε σφάλμα",
"Online Library": "Online Βιβλιοθήκη",
"URL must start with http:// or https://": "Το URL πρέπει να ξεκινά με http:// ή https://",
"Title, Author, Tag, etc...": "Τίτλος, Συγγραφέας, Ετικέτα, κ.λπ...",
"Query": "Ερώτημα",
"Subject": "Θέμα",
"Enter {{terms}}": "Εισαγάγετε {{terms}}",
"No search results found": "Δεν βρέθηκαν αποτελέσματα αναζήτησης",
"Failed to load OPDS feed: {{status}} {{statusText}}": "Αποτυχία φόρτωσης ροής OPDS: {{status}} {{statusText}}",
"Search in {{title}}": "Αναζήτηση στο {{title}}",
"Manage Storage": "Διαχείριση αποθήκευσης",
"Failed to load files": "Αποτυχία φόρτωσης αρχείων",
"Deleted {{count}} file(s)_one": "Διαγράφηκε {{count}} αρχείο",
"Deleted {{count}} file(s)_other": "Διαγράφηκαν {{count}} αρχεία",
"Failed to delete {{count}} file(s)_one": "Αποτυχία διαγραφής {{count}} αρχείου",
"Failed to delete {{count}} file(s)_other": "Αποτυχία διαγραφής {{count}} αρχείων",
"Failed to delete files": "Αποτυχία διαγραφής αρχείων",
"Total Files": "Σύνολο αρχείων",
"Total Size": "Συνολικό μέγεθος",
"Quota": "Όριο",
"Used": "Χρησιμοποιήθηκε",
"Files": "Αρχεία",
"Search files...": "Αναζήτηση αρχείων...",
"Newest First": "Νεότερα πρώτα",
"Oldest First": "Παλαιότερα πρώτα",
"Largest First": "Μεγαλύτερα πρώτα",
"Smallest First": "Μικρότερα πρώτα",
"Name A-Z": "Όνομα AZ",
"Name Z-A": "Όνομα ZA",
"{{count}} selected_one": "{{count}} επιλεγμένο",
"{{count}} selected_other": "{{count}} επιλεγμένα",
"Delete Selected": "Διαγραφή επιλεγμένων",
"Created": "Δημιουργήθηκε",
"No files found": "Δεν βρέθηκαν αρχεία",
"No files uploaded yet": "Δεν έχουν ανέβει αρχεία ακόμη",
"files": "αρχεία",
"Page {{current}} of {{total}}": "Σελίδα {{current}} από {{total}}",
"Are you sure to delete {{count}} selected file(s)?_one": "Σίγουρα θέλετε να διαγράψετε {{count}} επιλεγμένο αρχείο;",
"Are you sure to delete {{count}} selected file(s)?_other": "Σίγουρα θέλετε να διαγράψετε {{count}} επιλεγμένα αρχεία;",
"Cloud Storage Usage": "Χρήση αποθήκευσης cloud",
"Rename Group": "Μετονομασία ομάδας",
"From Directory": "Από κατάλογο",
"Successfully imported {{count}} book(s)_one": "Επιτυχής εισαγωγή 1 βιβλίου",
"Successfully imported {{count}} book(s)_other": "Επιτυχής εισαγωγή {{count}} βιβλίων",
"Count": "Πλήθος",
"Start Page": "Αρχική Σελίδα",
"Search in OPDS Catalog...": "Αναζήτηση στον κατάλογο OPDS...",
"Please log in to use advanced TTS features": "Παρακαλώ συνδεθείτε για να χρησιμοποιήσετε προηγμένες λειτουργίες TTS",
"Word limit of 30 words exceeded.": "Υπέρβαση ορίου 30 λέξεων.",
"Proofread": "Διόρθωση",
"Current selection": "Τρέχουσα επιλογή",
"All occurrences in this book": "Όλες οι εμφανίσεις σε αυτό το βιβλίο",
"All occurrences in your library": "Όλες οι εμφανίσεις στη βιβλιοθήκη σας",
"Selected text:": "Επιλεγμένο κείμενο:",
"Replace with:": "Αντικατάσταση με:",
"Enter text...": "Εισαγωγή κειμένου…",
"Case sensitive:": "Διάκριση πεζών-κεφαλαίων:",
"Scope:": "Εύρος εφαρμογής:",
"Selection": "Επιλογή",
"Library": "Βιβλιοθήκη",
"Yes": "Ναι",
"No": "Όχι",
"Proofread Replacement Rules": "Κανόνες αντικατάστασης διόρθωσης",
"Selected Text Rules": "Κανόνες επιλεγμένου κειμένου",
"No selected text replacement rules": "Δεν υπάρχουν κανόνες αντικατάστασης για το επιλεγμένο κείμενο",
"Book Specific Rules": "Κανόνες για συγκεκριμένο βιβλίο",
"No book-level replacement rules": "Δεν υπάρχουν κανόνες αντικατάστασης σε επίπεδο βιβλίου",
"Disable Quick Action": "Απενεργοποίηση γρήγορης ενέργειας",
"Enable Quick Action on Selection": "Ενεργοποίηση γρήγορης ενέργειας κατά την επιλογή",
"None": "Καμία",
"Annotation Tools": "Εργαλεία σχολιασμού",
"Enable Quick Actions": "Ενεργοποίηση γρήγορων ενεργειών",
"Quick Action": "Γρήγορη ενέργεια",
"Copy to Notebook": "Αντιγραφή στο σημειωματάριο",
"Copy text after selection": "Αντιγραφή κειμένου μετά την επιλογή",
"Highlight text after selection": "Επισήμανση κειμένου μετά την επιλογή",
"Annotate text after selection": "Σχολιασμός κειμένου μετά την επιλογή",
"Search text after selection": "Αναζήτηση κειμένου μετά την επιλογή",
"Look up text in dictionary after selection": "Αναζήτηση κειμένου στο λεξικό μετά την επιλογή",
"Look up text in Wikipedia after selection": "Αναζήτηση κειμένου στη Wikipedia μετά την επιλογή",
"Translate text after selection": "Μετάφραση κειμένου μετά την επιλογή",
"Read text aloud after selection": "Ανάγνωση κειμένου μετά την επιλογή",
"Proofread text after selection": "Διόρθωση κειμένου μετά την επιλογή",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} ενεργές, {{pendingCount}} σε αναμονή",
"{{failedCount}} failed": "{{failedCount}} απέτυχαν",
"Waiting...": "Αναμονή...",
"Failed": "Απέτυχε",
"Completed": "Ολοκληρώθηκε",
"Cancelled": "Ακυρώθηκε",
"Retry": "Επανάληψη",
"Active": "Ενεργές",
"Transfer Queue": "Ουρά μεταφορών",
"Upload All": "Ανέβασμα όλων",
"Download All": "Λήψη όλων",
"Resume Transfers": "Συνέχιση μεταφορών",
"Pause Transfers": "Παύση μεταφορών",
"Pending": "Σε αναμονή",
"No transfers": "Χωρίς μεταφορές",
"Retry All": "Επανάληψη όλων",
"Clear Completed": "Εκκαθάριση ολοκληρωμένων",
"Clear Failed": "Εκκαθάριση αποτυχημένων",
"Upload queued: {{title}}": "Ανέβασμα στην ουρά: {{title}}",
"Download queued: {{title}}": "Λήψη στην ουρά: {{title}}",
"Book not found in library": "Το βιβλίο δεν βρέθηκε στη βιβλιοθήκη",
"Unknown error": "Άγνωστο σφάλμα",
"Please log in to continue": "Παρακαλώ συνδεθείτε για να συνεχίσετε",
"Cloud File Transfers": "Μεταφορές αρχείων στο cloud",
"Show Search Results": "Εμφάνιση αποτελεσμάτων",
"Search results for '{{term}}'": "Αποτελέσματα για '{{term}}'",
"Close Search": "Κλείσιμο αναζήτησης",
"Previous Result": "Προηγούμενο αποτέλεσμα",
"Next Result": "Επόμενο αποτέλεσμα",
"Bookmarks": "Σελιδοδείκτες",
"Annotations": "Σχολιασμοί",
"Show Results": "Εμφάνιση αποτελεσμάτων",
"Clear search": "Εκκαθάριση αναζήτησης",
"Clear search history": "Εκκαθάριση ιστορικού αναζήτησης",
"Tap to Toggle Footer": "Πατήστε για εναλλαγή υποσέλιδου",
"Show Current Time": "Εμφάνιση τρέχουσας ώρας",
"Use 24 Hour Clock": "Χρήση 24ωρης μορφής ώρας",
"Show Current Battery Status": "Εμφάνιση τρέχουσας κατάστασης μπαταρίας",
"Exported successfully": "Εξαγωγή επιτυχής",
"Book exported successfully.": "Το βιβλίο εξήχθη επιτυχώς.",
"Failed to export the book.": "Αποτυχία εξαγωγής του βιβλίου.",
"Export Book": "Εξαγωγή βιβλίου",
"Whole word:": "Ολόκληρη λέξη:",
"Error": "Σφάλμα",
"Unable to load the article. Try searching directly on {{link}}.": "Αδυναμία φόρτωσης του άρθρου. Δοκιμάστε να αναζητήσετε απευθείας στο {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Αδυναμία φόρτωσης της λέξης. Δοκιμάστε να αναζητήσετε απευθείας στο {{link}}.",
"Date Published": "Ημερομηνία δημοσίευσης",
"Only for TTS:": "Μόνο για TTS:",
"Uploaded": "Μεταφορτώθηκε",
"Downloaded": "Λήφθηκε",
"Deleted": "Διαγράφηκε",
"Note:": "Σημείωση:",
"Time:": "Ώρα:",
"Format Options": "Επιλογές μορφοποίησης",
"Export Date": "Ημερομηνία εξαγωγής",
"Chapter Titles": "Τίτλοι κεφαλαίων",
"Chapter Separator": "Διαχωριστικό κεφαλαίων",
"Highlights": "Επισημάνσεις",
"Note Date": "Ημερομηνία σημείωσης",
"Advanced": "Για προχωρημένους",
"Hide": "Απόκρυψη",
"Show": "Εμφάνιση",
"Use Custom Template": "Χρήση προσαρμοσμένου προτύπου",
"Export Template": "Πρότυπο εξαγωγής",
"Template Syntax:": "Σύνταξη προτύπου:",
"Insert value": "Εισαγωγή τιμής",
"Format date (locale)": "Μορφοποίηση ημερομηνίας (τοπική)",
"Format date (custom)": "Μορφοποίηση ημερομηνίας (προσαρμοσμένη)",
"Conditional": "Υπό όρους",
"Loop": "Βρόχος",
"Available Variables:": "Διαθέσιμες μεταβλητές:",
"Book title": "Τίτλος βιβλίου",
"Book author": "Συγγραφέας βιβλίου",
"Export date": "Ημερομηνία εξαγωγής",
"Array of chapters": "Πίνακας κεφαλαίων",
"Chapter title": "Τίτλος κεφαλαίου",
"Array of annotations": "Πίνακας σχολιασμών",
"Highlighted text": "Επισημασμένο κείμενο",
"Annotation note": "Σημείωση σχολιασμού",
"Date Format Tokens:": "Σύμβολα μορφοποίησης ημερομηνίας:",
"Year (4 digits)": "Έτος (4 ψηφία)",
"Month (01-12)": "Μήνας (01-12)",
"Day (01-31)": "Ημέρα (01-31)",
"Hour (00-23)": "Ώρα (00-23)",
"Minute (00-59)": "Λεπτό (00-59)",
"Second (00-59)": "Δευτερόλεπτο (00-59)",
"Show Source": "Εμφάνιση πηγής",
"No content to preview": "Δεν υπάρχει περιεχόμενο για προεπισκόπηση",
"Export": "Εξαγωγή",
"Set Timeout": "Ορισμός χρονικού ορίου",
"Select Voice": "Επιλογή φωνής",
"Toggle Sticky Bottom TTS Bar": "Εναλλαγή καρφιτσωμένης μπάρας TTS",
"Display what I'm reading on Discord": "Εμφάνιση του βιβλίου που διαβάζω στο Discord",
"Show on Discord": "Εμφάνιση στο Discord",
"Instant {{action}}": "Άμεση {{action}}",
"Instant {{action}} Disabled": "Άμεση {{action}} απενεργοποιημένη",
"Annotation": "Σημείωση",
"Reset Template": "Επαναφορά προτύπου",
"Annotation style": "Στυλ σχολίου",
"Annotation color": "Χρώμα σχολίου",
"Annotation time": "Ώρα σχολίου",
"AI": "AI",
"Are you sure you want to re-index this book?": "Είστε σίγουροι ότι θέλετε να επαναδημιουργήσετε το ευρετήριο αυτού του βιβλίου;",
"Enable AI in Settings": "Ενεργοποίηση AI στις ρυθμίσεις",
"Index This Book": "Δημιουργία ευρετηρίου για αυτό το βιβλίο",
"Enable AI search and chat for this book": "Ενεργοποίηση αναζήτησης AI και συνομιλίας για αυτό το βιβλίο",
"Start Indexing": "Έναρξη δημιουργίας ευρετηρίου",
"Indexing book...": "Δημιουργία ευρετηρίου βιβλίου...",
"Preparing...": "Προετοιμασία...",
"Delete this conversation?": "Διαγραφή αυτής της συνομιλίας;",
"No conversations yet": "Δεν υπάρχουν συνομιλίες ακόμα",
"Start a new chat to ask questions about this book": "Ξεκινήστε μια νέα συνομιλία για να κάνετε ερωτήσεις σχετικά με αυτό το βιβλίο",
"Rename": "Μετονομασία",
"New Chat": "Νέα συνομιλία",
"Chat": "Συνομιλία",
"Please enter a model ID": "Εισάγετε ένα αναγνωριστικό μοντέλου",
"Model not available or invalid": "Το μοντέλο δεν είναι διαθέσιμο ή δεν είναι έγκυρο",
"Failed to validate model": "Αποτυχία επικύρωσης μοντέλου",
"Couldn't connect to Ollama. Is it running?": "Δεν ήταν δυνατή η σύνδεση με το Ollama. Εκτελείται;",
"Invalid API key or connection failed": "Μη έγκυρο κλειδί API ή αποτυχία σύνδεσης",
"Connection failed": "Αποτυχία σύνδεσης",
"AI Assistant": "Βοηθός AI",
"Enable AI Assistant": "Ενεργοποίηση βοηθού AI",
"Provider": "Πάροχος",
"Ollama (Local)": "Ollama (Τοπικό)",
"AI Gateway (Cloud)": "Πύλη AI (Cloud)",
"Ollama Configuration": "Διαμόρφωση Ollama",
"Refresh Models": "Ανανέωση μοντέλων",
"AI Model": "Μοντέλο AI",
"No models detected": "Δεν εντοπίστηκαν μοντέλα",
"AI Gateway Configuration": "Διαμόρφωση πύλης AI",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Επιλέξτε από μια συλλογή υψηλής ποιότητας, οικονομικών μοντέλων AI. Μπορείτε επίσης να χρησιμοποιήσετε το δικό σας μοντέλο επιλέγοντας \"Προσαρμοσμένο μοντέλο\" παρακάτω.",
"API Key": "Κλειδί API",
"Get Key": "Λήψη κλειδιού",
"Model": "Μοντέλο",
"Custom Model...": "Προσαρμοσμένο μοντέλο...",
"Custom Model ID": "Αναγνωριστικό προσαρμοσμένου μοντέλου",
"Validate": "Επικύρωση",
"Model available": "Το μοντέλο είναι διαθέσιμο",
"Connection": "Σύνδεση",
"Test Connection": "Δοκιμή σύνδεσης",
"Connected": "Συνδεδεμένο",
"Custom Colors": "Προσαρμοσμένα χρώματα",
"Color E-Ink Mode": "Λειτουργία έγχρωμου E-Ink",
"Reading Ruler": "Χάρακας ανάγνωσης",
"Enable Reading Ruler": "Ενεργοποίηση χάρακα ανάγνωσης",
"Lines to Highlight": "Γραμμές για επισήμανση",
"Ruler Color": "Χρώμα χάρακα",
"Command Palette": "Παλέτα εντολών",
"Search settings and actions...": "Αναζήτηση ρυθμίσεων και ενεργειών...",
"No results found for": "Δεν βρέθηκαν αποτελέσματα για",
"Type to search settings and actions": "Πληκτρολογήστε για αναζήτηση ρυθμίσεων και ενεργειών",
"Recent": "Πρόσφατα",
"navigate": "πλοήγηση",
"select": "επιλογή",
"close": "κλείσιμο",
"Search Settings": "Αναζήτηση ρυθμίσεων",
"Page Margins": "Περιθώρια σελίδας",
"AI Provider": "Πάροχος AI",
"Ollama URL": "URL Ollama",
"Ollama Model": "Μοντέλο Ollama",
"AI Gateway Model": "Μοντέλο AI Gateway",
"Actions": "Ενέργειες",
"Navigation": "Πλοήγηση",
"Set status for {{count}} book(s)_one": "Ορισμός κατάστασης για {{count}} βιβλίο",
"Set status for {{count}} book(s)_other": "Ορισμός κατάστασης για {{count}} βιβλία",
"Mark as Unread": "Σήμανση ως μη αναγνωσμένο",
"Mark as Finished": "Σήμανση ως ολοκληρωμένο",
"Finished": "Ολοκληρώθηκε",
"Unread": "Μη αναγνωσμένο",
"Clear Status": "Εκκαθάριση κατάστασης",
"Status": "Κατάσταση",
"Loading": "Φόρτωση...",
"Exit Paragraph Mode": "Έξοδος από τη λειτουργία παραγράφου",
"Paragraph Mode": "Λειτουργία παραγράφου",
"Embedding Model": "Μοντέλο ενσωμάτωσης",
"{{count}} book(s) synced_one": "{{count}} βιβλίο συγχρονίστηκε",
"{{count}} book(s) synced_other": "{{count}} βιβλία συγχρονίστηκαν",
"Unable to start RSVP": "Αδυναμία έναρξης RSVP",
"RSVP not supported for PDF": "Το RSVP δεν υποστηρίζεται για PDF",
"Select Chapter": "Επιλογή Κεφαλαίου",
"Context": "Πλαίσιο",
"Ready": "Έτοιμο",
"Chapter Progress": "Πρόοδος Κεφαλαίου",
"words": "λέξεις",
"{{time}} left": "{{time}} απομένουν",
"Reading progress": "Πρόοδος ανάγνωσης",
"Skip back 15 words": "Επιστροφή 15 λέξεων",
"Back 15 words (Shift+Left)": "Πίσω 15 λέξεις (Shift+Αριστερά)",
"Pause (Space)": "Παύση (Διάστημα)",
"Play (Space)": "Αναπαραγωγή (Διάστημα)",
"Skip forward 15 words": "Προώθηση 15 λέξεων",
"Forward 15 words (Shift+Right)": "Εμπρός 15 λέξεις (Shift+Δεξιά)",
"Decrease speed": "Μείωση ταχύτητας",
"Slower (Left/Down)": "Πιο αργά (Αριστερά/Κάτω)",
"Increase speed": "Αύξηση ταχύτητας",
"Faster (Right/Up)": "Πιο γρήγορα (Δεξιά/Πάνω)",
"Start RSVP Reading": "Έναρξη ανάγνωσης RSVP",
"Choose where to start reading": "Επιλέξτε από πού θα ξεκινήσετε την ανάγνωση",
"From Chapter Start": "Από την αρχή του κεφαλαίου",
"Start reading from the beginning of the chapter": "Ξεκινήστε την ανάγνωση από την αρχή του κεφαλαίου",
"Resume": "Συνέχεια",
"Continue from where you left off": "Συνεχίστε από εκεί που σταματήσατε",
"From Current Page": "Από την τρέχουσα σελίδα",
"Start from where you are currently reading": "Ξεκινήστε από εκεί που διαβάζετε αυτή τη στιγμή",
"From Selection": "Από την επιλογή",
"Speed Reading Mode": "Λειτουργία ταχείας ανάγνωσης",
"Scroll left": "Κύλιση αριστερά",
"Scroll right": "Κύλιση δεξιά",
"Library Sync Progress": "Πρόοδος συγχρονισμού βιβλιοθήκης",
"Back to library": "Επιστροφή στη βιβλιοθήκη",
"Group by...": "Ομαδοποίηση κατά...",
"Export as Plain Text": "Αποστολή ως απλό κείμενο",
"Export as Markdown": "Αποστολή ως Markdown",
"Show Page Navigation Buttons": "Κουμπιά πλοήγησης",
"Page {{number}}": "Σελίδα {{number}}",
"highlight": "επισήμανση",
"underline": "υπογράμμιση",
"squiggly": "κυματιστή γραμμή",
"red": "κόκκινο",
"violet": "βιολετί",
"blue": "μπλε",
"green": "πράσινο",
"yellow": "κίτρινο",
"Select {{style}} style": "Επιλέξτε στυλ {{style}}",
"Select {{color}} color": "Επιλέξτε χρώμα {{color}}",
"Close Book": "Κλείσιμο βιβλίου",
"Speed Reading": "Γρήγορη Ανάγνωση",
"Close Speed Reading": "Κλείσιμο Γρήγορης Ανάγνωσης",
"Authors": "Συγγραφείς",
"Books": "Βιβλία",
"Groups": "Ομάδες",
"Back to TTS Location": "Επιστροφή στην τοποθεσία TTS",
"Metadata": "Μεταδεδομένα",
"Image viewer": "Πρόγραμμα προβολής εικόνων",
"Previous Image": "Προηγούμενη εικόνα",
"Next Image": "Επόμενη εικόνα",
"Zoomed": "Ζουμαρισμένο",
"Zoom level": "Επίπεδο ζουμ",
"Table viewer": "Πρόγραμμα προβολής πινάκων",
"Unable to connect to Readwise. Please check your network connection.": "Αδυναμία σύνδεσης στο Readwise. Ελέγξτε τη σύνδεση του δικτύου σας.",
"Invalid Readwise access token": "Μη έγκυρο διακριτικό πρόσβασης Readwise",
"Disconnected from Readwise": "Αποσυνδέθηκε από το Readwise",
"Never": "Ποτέ",
"Readwise Settings": "Ρυθμίσεις Readwise",
"Connected to Readwise": "Συνδέθηκε στο Readwise",
"Last synced: {{time}}": "Τελευταίος συγχρονισμός: {{time}}",
"Sync Enabled": "Ο συγχρονισμός ενεργοποιήθηκε",
"Disconnect": "Αποσύνδεση",
"Connect your Readwise account to sync highlights.": "Συνδέστε τον λογαριασμό σας Readwise για να συγχρονίσετε τις επισημάνσεις.",
"Get your access token at": "Αποκτήστε το διακριτικό πρόσβασής σας στο",
"Access Token": "Διακριτικό πρόσβασης",
"Paste your Readwise access token": "Επικολλήστε το διακριτικό πρόσβασης Readwise",
"Config": "Ρύθμιση παραμέτρων",
"Readwise Sync": "Συγχρονισμός Readwise",
"Push Highlights": "Προώθηση επισημάνσεων",
"Highlights synced to Readwise": "Οι επισημάνσεις συγχρονίστηκαν στο Readwise",
"Readwise sync failed: no internet connection": "Ο συγχρονισμός Readwise απέτυχε: δεν υπάρχει σύνδεση στο διαδίκτυο",
"Readwise sync failed: {{error}}": "Ο συγχρονισμός Readwise απέτυχε: {{error}}",
"System Screen Brightness": "Φωτεινότητα οθόνης συστήματος",
"Page:": "Σελίδα:",
"Page: {{number}}": "Σελίδα: {{number}}",
"Annotation page number": "Αριθμός σελίδας σχολίου",
"Translating...": "Μετάφραση...",
"Show Battery Percentage": "Εμφάνιση ποσοστού μπαταρίας",
"Hide Scrollbar": "Απόκρυψη γραμμής κύλισης",
"Skip to last reading position": "Μετάβαση στην τελευταία θέση ανάγνωσης",
"Show context": "Εμφάνιση πλαισίου",
"Hide context": "Απόκρυψη πλαισίου",
"Decrease font size": "Μείωση μεγέθους γραμματοσειράς",
"Increase font size": "Αύξηση μεγέθους γραμματοσειράς",
"Focus": "Εστίαση",
"Theme color": "Χρώμα θέματος",
"Import failed": "Η εισαγωγή απέτυχε",
"Available Formatters:": "Διαθέσιμοι μορφοποιητές:",
"Format date": "Μορφοποίηση ημερομηνίας",
"Markdown block quote (> per line)": "Παράθεση Markdown (> ανά γραμμή)",
"Newlines to <br>": "Αλλαγές γραμμής σε <br>",
"Change case": "Αλλαγή πεζών/κεφαλαίων",
"Trim whitespace": "Αφαίρεση κενών",
"Truncate to n characters": "Περικοπή σε n χαρακτήρες",
"Replace text": "Αντικατάσταση κειμένου",
"Fallback value": "Εναλλακτική τιμή",
"Get length": "Λήψη μήκους",
"First/last element": "Πρώτο/τελευταίο στοιχείο",
"Join array": "Ένωση πίνακα",
"Backup failed: {{error}}": "Η δημιουργία αντιγράφου ασφαλείας απέτυχε: {{error}}",
"Select Backup": "Επιλογή αντιγράφου ασφαλείας",
"Restore failed: {{error}}": "Η επαναφορά απέτυχε: {{error}}",
"Backup & Restore": "Αντίγραφα ασφαλείας & Επαναφορά",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "Δημιουργήστε αντίγραφο ασφαλείας της βιβλιοθήκης σας ή επαναφέρετε από προηγούμενο αντίγραφο. Η επαναφορά θα συγχωνευθεί με την τρέχουσα βιβλιοθήκη σας.",
"Backup Library": "Αντίγραφο βιβλιοθήκης",
"Restore Library": "Επαναφορά βιβλιοθήκης",
"Creating backup...": "Δημιουργία αντιγράφου ασφαλείας...",
"Restoring library...": "Επαναφορά βιβλιοθήκης...",
"{{current}} of {{total}} items": "{{current}} από {{total}} στοιχεία",
"Backup completed successfully!": "Το αντίγραφο ασφαλείας ολοκληρώθηκε!",
"Restore completed successfully!": "Η επαναφορά ολοκληρώθηκε!",
"Your library has been saved to the selected location.": "Η βιβλιοθήκη σας αποθηκεύτηκε στην επιλεγμένη τοποθεσία.",
"{{added}} books added, {{updated}} books updated.": "{{added}} βιβλία προστέθηκαν, {{updated}} βιβλία ενημερώθηκαν.",
"Operation failed": "Η λειτουργία απέτυχε",
"Loading library...": "Φόρτωση βιβλιοθήκης...",
"{{count}} books refreshed_one": "{{count}} βιβλίο ανανεώθηκε",
"{{count}} books refreshed_other": "{{count}} βιβλία ανανεώθηκαν",
"Failed to refresh metadata": "Αποτυχία ανανέωσης μεταδεδομένων",
"Refresh Metadata": "Ανανέωση μεταδεδομένων",
"Keyboard Shortcuts": "Συντομεύσεις πληκτρολογίου",
"View all keyboard shortcuts": "Προβολή όλων των συντομεύσεων",
"Switch Sidebar Tab": "Εναλλαγή καρτέλας πλαϊνής γραμμής",
"Toggle Notebook": "Εμφάνιση/Απόκρυψη σημειωματάριου",
"Search in Book": "Αναζήτηση στο βιβλίο",
"Toggle Scroll Mode": "Εναλλαγή λειτουργίας κύλισης",
"Toggle Select Mode": "Εναλλαγή λειτουργίας επιλογής",
"Toggle Bookmark": "Εναλλαγή σελιδοδείκτη",
"Toggle Text to Speech": "Εναλλαγή κειμένου σε ομιλία",
"Play / Pause TTS": "Αναπαραγωγή / Παύση TTS",
"Toggle Paragraph Mode": "Εναλλαγή λειτουργίας παραγράφου",
"Highlight Selection": "Επισήμανση επιλογής",
"Underline Selection": "Υπογράμμιση επιλογής",
"Annotate Selection": "Σχολιασμός επιλογής",
"Search Selection": "Αναζήτηση επιλογής",
"Copy Selection": "Αντιγραφή επιλογής",
"Translate Selection": "Μετάφραση επιλογής",
"Dictionary Lookup": "Αναζήτηση στο λεξικό",
"Wikipedia Lookup": "Αναζήτηση στη Wikipedia",
"Read Aloud Selection": "Ανάγνωση επιλογής",
"Proofread Selection": "Διόρθωση επιλογής",
"Open Settings": "Άνοιγμα ρυθμίσεων",
"Open Command Palette": "Άνοιγμα παλέτας εντολών",
"Show Keyboard Shortcuts": "Εμφάνιση συντομεύσεων",
"Open Books": "Άνοιγμα βιβλίων",
"Toggle Fullscreen": "Εναλλαγή πλήρους οθόνης",
"Close Window": "Κλείσιμο παραθύρου",
"Quit App": "Έξοδος εφαρμογής",
"Go Left / Previous Page": "Αριστερά / Προηγούμενη σελίδα",
"Go Right / Next Page": "Δεξιά / Επόμενη σελίδα",
"Go Up": "Πάνω",
"Go Down": "Κάτω",
"Previous Chapter": "Προηγούμενο κεφάλαιο",
"Next Chapter": "Επόμενο κεφάλαιο",
"Scroll Half Page Down": "Κύλιση μισής σελίδας κάτω",
"Scroll Half Page Up": "Κύλιση μισής σελίδας πάνω",
"Save Note": "Αποθήκευση σημείωσης",
"Single Section Scroll": "Κύλιση μεμονωμένης ενότητας",
"General": "Γενικά",
"Text to Speech": "Κείμενο σε ομιλία",
"Zoom": "Ζουμ",
"Window": "Παράθυρο",
"Your Bookshelf": "Η βιβλιοθήκη σου",
"TTS": "Εκφώνηση",
"Media Info": "Πληροφορίες μέσων",
"Update Frequency": "Συχνότητα ενημέρωσης",
"Every Sentence": "Κάθε πρόταση",
"Every Paragraph": "Κάθε παράγραφο",
"Every Chapter": "Κάθε κεφάλαιο",
"TTS Media Info Update Frequency": "Συχνότητα ενημέρωσης πληροφοριών μέσων TTS",
"Select reading speed": "Επιλέξτε ταχύτητα ανάγνωσης",
"Drag to seek": "Σύρετε για αναζήτηση",
"Punctuation Delay": "Καθυστέρηση στίξης",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "Επιβεβαιώστε ότι αυτή η σύνδεση OPDS θα δρομολογηθεί μέσω των διακομιστών Readest στην εφαρμογή ιστού πριν συνεχίσετε.",
"Custom Headers": "Προσαρμοσμένες κεφαλίδες",
"Custom Headers (optional)": "Προσαρμοσμένες κεφαλίδες (προαιρετικό)",
"Add one header per line using \"Header-Name: value\".": "Προσθέστε μία κεφαλίδα ανά γραμμή χρησιμοποιώντας \"Header-Name: value\".",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "Κατανοώ ότι αυτή η σύνδεση OPDS θα δρομολογηθεί μέσω των διακομιστών Readest στην εφαρμογή ιστού. Αν δεν εμπιστεύομαι τo Readest με αυτά τα διαπιστευτήρια ή τις κεφαλίδες, θα πρέπει να χρησιμοποιήσω την εγγενή εφαρμογή.",
"Unable to connect to Hardcover. Please check your network connection.": "Αδυναμία σύνδεσης στο Hardcover. Ελέγξτε τη σύνδεση δικτύου σας.",
"Invalid Hardcover API token": "Μη έγκυρο Hardcover API token",
"Disconnected from Hardcover": "Αποσυνδέθηκε από το Hardcover",
"Hardcover Settings": "Ρυθμίσεις Hardcover",
"Connected to Hardcover": "Συνδεδεμένο στο Hardcover",
"Connect your Hardcover account to sync reading progress and notes.": "Συνδέστε τον λογαριασμό σας Hardcover για συγχρονισμό προόδου ανάγνωσης και σημειώσεων.",
"Get your API token from hardcover.app → Settings → API.": "Λάβετε το API token σας από hardcover.app → Ρυθμίσεις → API.",
"API Token": "API Token",
"Paste your Hardcover API token": "Επικολλήστε το Hardcover API token σας",
"Hardcover sync enabled for this book": "Ο συγχρονισμός Hardcover ενεργοποιήθηκε για αυτό το βιβλίο",
"Hardcover sync disabled for this book": "Ο συγχρονισμός Hardcover απενεργοποιήθηκε για αυτό το βιβλίο",
"Hardcover Sync": "Συγχρονισμός Hardcover",
"Enable for This Book": "Ενεργοποίηση για αυτό το βιβλίο",
"Push Notes": "Αποστολή σημειώσεων",
"Enable Hardcover sync for this book first.": "Ενεργοποιήστε πρώτα τον συγχρονισμό Hardcover για αυτό το βιβλίο.",
"No annotations or excerpts to sync for this book.": "Δεν υπάρχουν σχολιασμοί ή αποσπάσματα για συγχρονισμό σε αυτό το βιβλίο.",
"Configure Hardcover in Settings first.": "Ρυθμίστε πρώτα το Hardcover στις Ρυθμίσεις.",
"No new Hardcover note changes to sync.": "Δεν υπάρχουν νέες αλλαγές σημειώσεων Hardcover για συγχρονισμό.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover συγχρονίστηκε: {{inserted}} νέα, {{updated}} ενημερωμένα, {{skipped}} αμετάβλητα",
"Hardcover notes sync failed: {{error}}": "Αποτυχία συγχρονισμού σημειώσεων Hardcover: {{error}}",
"Reading progress synced to Hardcover": "Η πρόοδος ανάγνωσης συγχρονίστηκε στο Hardcover",
"Hardcover progress sync failed: {{error}}": "Αποτυχία συγχρονισμού προόδου Hardcover: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "Διατήρηση υπάρχοντος αναγνωριστικού πηγής",
"Toggle Toolbar": "Εναλλαγή γραμμής εργαλείων"
}
@@ -1,13 +1,27 @@
{
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Are you sure to delete {{count}} selected book(s)?_one": "Are you sure to delete {{count}} selected book?",
"Are you sure to delete {{count}} selected book(s)?_other": "Are you sure to delete {{count}} selected books?",
"Search in {{count}} Book(s)..._one": "Search in {{count}} book...",
"Search in {{count}} Book(s)..._other": "Search in {{count}} books...",
"{{count}} pages left in chapter_one": "{{count}} page left in chapter",
"{{count}} pages left in chapter_other": "{{count}} pages left in chapter"
"{{count}} pages left in chapter_one": "<0>{{count}}</0><1> page left in chapter</1>",
"{{count}} pages left in chapter_other": "<0>{{count}}</0><1> pages left in chapter</1>",
"Deleted {{count}} file(s)_one": "Deleted {{count}} file",
"Deleted {{count}} file(s)_other": "Deleted {{count}} files",
"Failed to delete {{count}} file(s)_one": "Failed to delete {{count}} file",
"Failed to delete {{count}} file(s)_other": "Failed to delete {{count}} files",
"{{count}} selected_one": "{{count}} selected",
"{{count}} selected_other": "{{count}} selected",
"Are you sure to delete {{count}} selected file(s)?_one": "Are you sure to delete {{count}} selected file?",
"Are you sure to delete {{count}} selected file(s)?_other": "Are you sure to delete {{count}} selected files?",
"Successfully imported {{count}} book(s)_one": "Successfully imported {{count}} book",
"Successfully imported {{count}} book(s)_other": "Successfully imported {{count}} books",
"Set status for {{count}} book(s)_one": "Set status for {{count}} book",
"Set status for {{count}} book(s)_other": "Set status for {{count}} books",
"{{count}} book(s) synced_one": "{{count}} book synced",
"{{count}} book(s) synced_other": "{{count}} books synced"
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,6 @@
"Auto Mode": "स्वचालित मोड",
"Behavior": "व्यवहार",
"Book": "पुस्तक",
"Book Cover": "पुस्तक का कवर",
"Bookmark": "बुकमार्क",
"Cancel": "रद्द करें",
"Chapter": "अध्याय",
@@ -46,7 +45,6 @@
"Horizontal Direction": "क्षैतिज दिशा",
"Hyphenation": "हाइफ़नेशन",
"Import Books": "पुस्तकें आयात करें",
"Language:": "भाषा:",
"Layout": "लेआउट",
"Light Mode": "लाइट मोड",
"Loading...": "लोड हो रहा है...",
@@ -68,8 +66,8 @@
"Paging Animation": "पेजिंग एनीमेशन",
"Paragraph": "पैराग्राफ",
"Parallel Read": "समानांतर पढ़ें",
"Published:": "प्रकाशित:",
"Publisher:": "प्रकाशक:",
"Published": "प्रकाशित",
"Publisher": "प्रकाशक",
"Reading Progress Synced": "पढ़ने की प्रगति सिंक की गई",
"Reload Page": "पृष्ठ रीलोड करें",
"Reveal in File Explorer": "फ़ाइल एक्सप्लोरर में दिखाएं",
@@ -83,7 +81,6 @@
"Search...": "खोजें...",
"Select Book": "पुस्तक चुनें",
"Select Books": "पुस्तकें चुनें",
"Select Multiple Books": "कई पुस्तकें चुनें",
"Sepia": "सेपिया",
"Serif Font": "सेरिफ फ़ॉन्ट",
"Show Book Details": "पुस्तक विवरण दिखाएं",
@@ -94,23 +91,21 @@
"Slow": "धीमा",
"Solarized": "सोलराइज्ड",
"Speak": "बोलें",
"Subjects:": "विषय:",
"Subjects": "विषय",
"System Fonts": "सिस्टम फ़ॉन्ट्स",
"TTS not supported in this device": "यह डिवाइस TTS का समर्थन नहीं करता",
"Theme Color": "थीम रंग",
"Theme Mode": "थीम मोड",
"Translate": "अनुवाद करें",
"Translated Text": "अनुवादित पाठ",
"Unknown": "अज्ञात",
"Untitled": "शीर्षकहीन",
"Updated:": "अपडेट किया गया:",
"Updated": "अपडेट किया गया",
"Version {{version}}": "संस्करण {{version}}",
"Vertical Direction": "ऊर्ध्वाधर दिशा",
"Welcome to your library. You can import your books here and read them anytime.": "आपकी लाइब्रेरी में आपका स्वागत है। आप यहां अपनी पुस्तकें आयात कर सकते हैं और कभी भी पढ़ सकते हैं।",
"Wikipedia": "विकिपीडिया",
"Writing Mode": "लेखन मोड",
"Your Library": "आपकी लाइब्रेरी",
"TTS not supported for PDF": "PDF के लिए TTS समर्थित नहीं है",
"Override Book Font": "पुस्तक फ़ॉन्ट ओवरराइड करें",
"Apply to All Books": "सभी पुस्तकों पर लागू करें",
"Apply to This Book": "इस पुस्तक पर लागू करें",
@@ -120,6 +115,7 @@
"Book Details": "पुस्तक विवरण",
"From Local File": "स्थानीय फ़ाइल से",
"TOC": "सामग्री",
"Table of Contents": "सामग्री",
"Book uploaded: {{title}}": "पुस्तक अपलोड की गई: {{title}}",
"Failed to upload book: {{title}}": "पुस्तक अपलोड करने में विफल: {{title}}",
"Book downloaded: {{title}}": "पुस्तक डाउनलोड की गई: {{title}}",
@@ -176,9 +172,6 @@
"Token": "टोकन",
"Your OTP token": "आपका ओटीपी टोकन",
"Verify token": "टोकन सत्यापित करें",
"Sign in with Google": "Google के साथ साइन इन करें",
"Sign in with Apple": "Apple के साथ साइन इन करें",
"Sign in with GitHub": "GitHub के साथ साइन इन करें",
"Account": "खाता",
"Failed to delete user. Please try again later.": "उपयोगकर्ता को हटाने में विफल। कृपया बाद में पुनः प्रयास करें।",
"Community Support": "सामुदायिक सहायता",
@@ -191,12 +184,11 @@
"RTL Direction": "RTL दिशा",
"Maximum Column Height": "कॉलम की अधिकतम ऊँचाई",
"Maximum Column Width": "कॉलम की अधिकतम चौड़ाई",
"Continuous Scroll": "निरंतर स्क्रॉल",
"Fullscreen": "पूर्णस्क्रीन",
"No supported files found. Supported formats: {{formats}}": "कोई समर्थित फ़ाइलें नहीं मिलीं। समर्थित प्रारूप: {{formats}}",
"Drop to Import Books": "पुस्तकें आयात करने के लिए छोड़ें",
"Custom": "कस्टम",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "पूरी दुनिया एक स्टेज है,\nऔर सभी आदमी और महिलाएँ केवल अभिनेता हैं;\nउनके निकास और प्रवेश होते हैं,\nऔर एक आदमी अपने समय में कई भूमिकाएँ निभाता है,\nउसके कार्य सात युग होते हैं।\n\n— विलियम शेक्सपियर",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "पूरी दुनिया एक स्टेज है,\nऔर सभी आदमी और महिलाएँ केवल अभिनेता हैं;\nउनके निकास और प्रवेश होते हैं,\nऔर एक आदमी अपने समय में कई भूमिकाएँ निभाता है,\nउसके कार्य सात युग होते हैं।\n\n— विलियम शेक्सपियर",
"Custom Theme": "कस्टम थीम",
"Theme Name": "थीम का नाम",
"Text Color": "टेक्स्ट रंग",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "फ़ाइल खोलने पर स्वचालित आयात",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "कोई अध्याय नहीं मिला।",
"Failed to parse the EPUB file.": "EPUB फ़ाइल को पार्स करने में विफल।",
"This book format is not supported.": "यह पुस्तक प्रारूप समर्थित नहीं है।",
"No chapters detected": "कोई अध्याय नहीं मिला।",
"Failed to parse the EPUB file": "EPUB फ़ाइल को पार्स करने में विफल।",
"This book format is not supported": "यह पुस्तक प्रारूप समर्थित नहीं है।",
"Unable to fetch the translation. Please log in first and try again.": "अनुवाद प्राप्त करने में असमर्थ। कृपया पहले लॉग इन करें और पुनः प्रयास करें।",
"Group": "समूह",
"Always on Top": "सर्वोच्च पर हमेशा",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "डाउनलोड कर रहा है {{downloaded}} का {{contentLength}}",
"Download finished": "डाउनलोड पूरा हुआ",
"DOWNLOAD & INSTALL": "डाउनलोड और इंस्टॉल करें",
"Changelog:": "चेंजलॉग:",
"Changelog": "चेंजलॉग",
"Software Update": "सॉफ़्टवेयर अपडेट",
"Title": "शीर्षक",
"Date Read": "पढ़ने की तारीख",
@@ -253,18 +245,15 @@
"Ascending": "आरोही",
"Descending": "अवरोही",
"Sort by...": "द्वारा क्रमबद्ध करें...",
"Added:": "जोड़ा गया:",
"Format:": "फॉर्मेट:",
"Added": "जोड़ा गया",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "विवरण:",
"Description": "विवरण",
"No description available": "कोई विवरण उपलब्ध नहीं है",
"List": "सूची",
"Grid": "ग्रिड",
"(from 'As You Like It', Act II)": "('जैसा आप इसे पसंद करते हैं', अधिनियम II)",
"Link Color": "लिंक रंग",
"Volume Keys for Page Flip": "पृष्ठ फ़्लिप के लिए वॉल्यूम कुंजियाँ",
"Clicks for Page Flip": "पृष्ठ फ़्लिप के लिए क्लिक करें",
"Swap Clicks Area": "क्लिक क्षेत्र स्वैप करें",
"Screen": "स्क्रीन",
"Orientation": "अवयव",
"Portrait": "पोर्ट्रेट",
@@ -273,7 +262,7 @@
"Checking for updates...": "अपडेट की जांच कर रहा है...",
"Error checking for updates": "अपडेट की जांच करते समय त्रुटि",
"Details": "विवरण",
"File Size:": "फ़ाइल आकार:",
"File Size": "फ़ाइल आकार",
"Auto Detect": "स्वचालित पहचान",
"Next Section": "अगला अनुभाग",
"Previous Section": "पिछला अनुभाग",
@@ -300,7 +289,6 @@
"Disable Translation": "अनुवाद अक्षम करें",
"Scroll": "स्क्रॉल",
"Overlap Pixels": "ओवरलैप पिक्सेल",
"Click": "क्लिक करें",
"System Language": "सिस्टम भाषा",
"Security": "सुरक्षा",
"Allow JavaScript": "जावास्क्रिप्ट की अनुमति दें",
@@ -314,7 +302,6 @@
"Synced at {{time}}": "{{time}} पर सिंक किया गया",
"Never synced": "कभी सिंक नहीं किया गया",
"Show Remaining Time": "शेष समय दिखाएं",
"Show Page Number": "पृष्ठ संख्या दिखाएं",
"{{time}} min left in chapter": "{{time}} मिनट शेष अध्याय में",
"Override Book Color": "पुस्तक रंग ओवरराइड करें",
"Login Required": "लॉगिन ज़रूरी",
@@ -337,7 +324,6 @@
"Left Margin (px)": "बायां हाशिया (px)",
"Column Gap (%)": "स्तंभों के बीच की दूरी (%)",
"Always Show Status Bar": "स्थिति पट्टी हमेशा दिखाएं",
"Translation Not Available": "अनुवाद उपलब्ध नहीं है",
"Custom Content CSS": "सामग्री का CSS",
"Enter CSS for book content styling...": "पुस्तक सामग्री के लिए CSS दर्ज करें...",
"Custom Reader UI CSS": "इंटरफ़ेस का CSS",
@@ -347,11 +333,11 @@
"Fit": "फिट",
"Reset {{settings}}": "रीसेट {{settings}}",
"Reset Settings": "सेटिंग्स रीसेट करें",
"{{count}} pages left in chapter_one": "इस अध्याय में {{count}} पृष्ठ शेष हैं",
"{{count}} pages left in chapter_other": "इस अध्याय में {{count}} पृष्ठ शेष हैं",
"{{count}} pages left in chapter_one": "<1>इस अध्याय में </1><0>{{count}}</0><1> पृष्ठ शेष हैं</1>",
"{{count}} pages left in chapter_other": "<1>इस अध्याय में </1><0>{{count}}</0><1> पृष्ठ शेष हैं</1>",
"Show Remaining Pages": "शेष पृष्ठ दिखाएँ",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "सदस्यता प्रबंधित करें",
"Coming Soon": "जल्द आ रहा है",
@@ -359,7 +345,6 @@
"Upgrade to Plus or Pro": "Plus या Pro में अपग्रेड करें",
"Current Plan": "वर्तमान योजना",
"Plan Limits": "योजना की सीमाएँ",
"Failed to manage subscription. Please try again later.": "सदस्यता प्रबंधित करने में विफल। कृपया बाद में पुनः प्रयास करें।",
"Processing your payment...": "आपका भुगतान संसाधित हो रहा है...",
"Please wait while we confirm your subscription.": "कृपया प्रतीक्षा करें, हम आपकी सदस्यता की पुष्टि कर रहे हैं।",
"Payment Processing": "भुगतान संसाधित हो रहा है",
@@ -372,7 +357,6 @@
"Email:": "ईमेल:",
"Plan:": "योजना:",
"Amount:": "राशि:",
"Subscription ID:": "सदस्यता आईडी:",
"Go to Library": "लाइब्रेरी पर जाएँ",
"Need help? Contact our support team at support@readest.com": "मदद चाहिए? हमारी सहायता टीम से संपर्क करें: support@readest.com",
"Free Plan": "मुफ्त योजना",
@@ -402,7 +386,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "जितना चाहें उतना ऑडियो में सुनें।",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "अधिक अनुवाद और उन्नत विकल्प पाएं।",
"DeepL Pro Access": "DeepL प्रो एक्सेस",
"2 GB Cloud Sync Storage": "2 जीबी क्लाउड स्टोरेज",
"Enjoy faster responses and dedicated assistance whenever you need help.": "प्राथमिक सहायता पाएं।",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "दैनिक सीमा पूरी हुई। योजना बढ़ाएं।",
"Includes All Plus Plan Benefits": "सभी प्लस प्लान लाभ शामिल",
@@ -412,10 +395,793 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "स्मार्ट पढ़ने, अनुवाद और कंटेंट खोजने के लिए शक्तिशाली AI उपकरण का उपयोग करें।",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "सबसे सटीक अनुवाद इंजन के साथ दैनिक 1 लाख तक अक्षर अनुवाद करें।",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "सबसे सटीक अनुवाद इंजन के साथ दैनिक 5 लाख तक अक्षर अनुवाद करें।",
"10 GB Cloud Sync Storage": "10 GB क्लाउड सिंक स्टोरेज",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "2 GB सुरक्षित क्लाउड स्टोरेज के साथ अपना संपूर्ण पठन संग्रह संग्रहीत करें।",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "10 GB सुरक्षित क्लाउड स्टोरेज के साथ अपना संपूर्ण पठन संग्रह संग्रहीत करें।",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "5 GB सुरक्षित क्लाउड स्टोरेज के साथ अपना संपूर्ण पठन संग्रह संग्रहीत करें।",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "20 GB सुरक्षित क्लाउड स्टोरेज के साथ अपना संपूर्ण पठन संग्रह संग्रहीत करें।",
"Deleted cloud backup of the book: {{title}}": "पुस्तक का क्लाउड बैकअप हटाया गया: {{title}}",
"Failed to delete cloud backup of the book": "पुस्तक का क्लाउड बैकअप हटाने में विफल",
"Are you sure to delete the cloud backup of the selected book?": "क्या आप सुनिश्चित हैं कि आप चयनित पुस्तक का क्लाउड बैकअप हटाना चाहते हैं?"
"Are you sure to delete the cloud backup of the selected book?": "क्या आप सुनिश्चित हैं कि आप चयनित पुस्तक का क्लाउड बैकअप हटाना चाहते हैं?",
"What's New in Readest": "Readest में नया क्या है",
"Enter book title": "पुस्तक का शीर्षक दर्ज करें",
"Subtitle": "उपशीर्षक",
"Enter book subtitle": "पुस्तक का उपशीर्षक दर्ज करें",
"Enter author name": "लेखक का नाम दर्ज करें",
"Series": "श्रृंखला",
"Enter series name": "श्रृंखला का नाम दर्ज करें",
"Series Index": "श्रृंखला संख्या",
"Enter series index": "श्रृंखला संख्या दर्ज करें",
"Total in Series": "श्रृंखला में कुल",
"Enter total books in series": "श्रृंखला में कुल पुस्तकों की संख्या दर्ज करें",
"Enter publisher": "प्रकाशक का नाम दर्ज करें",
"Publication Date": "प्रकाशन दिनांक",
"Identifier": "पहचानकर्ता",
"Enter book description": "पुस्तक का विवरण दर्ज करें",
"Change cover image": "कवर इमेज बदलें",
"Replace": "बदलें",
"Unlock cover": "कवर अनलॉक करें",
"Lock cover": "कवर लॉक करें",
"Auto-Retrieve Metadata": "मेटाडेटा स्वचालित रूप से प्राप्त करें",
"Auto-Retrieve": "स्वचालित प्राप्ति",
"Unlock all fields": "सभी फील्ड अनलॉक करें",
"Unlock All": "सभी अनलॉक करें",
"Lock all fields": "सभी फील्ड लॉक करें",
"Lock All": "सभी लॉक करें",
"Reset": "रीसेट",
"Edit Metadata": "मेटाडेटा संपादित करें",
"Locked": "लॉक है",
"Select Metadata Source": "मेटाडेटा स्रोत चुनें",
"Keep manual input": "मैन्युअल इनपुट रखें",
"Google Books": "गूगल बुक्स",
"Open Library": "ओपन लाइब्रेरी",
"Fiction, Science, History": "काल्पनिक, विज्ञान, इतिहास",
"Open Book in New Window": "नई विंडो में पुस्तक खोलें",
"Voices for {{lang}}": "{{lang}} के लिए आवाज़ें",
"Yandex Translate": "यांडेक्स अनुवाद",
"YYYY or YYYY-MM-DD": "YYYY या YYYY-MM-DD",
"Restore Purchase": "खरीदारी पुनर्स्थापित करें",
"No purchases found to restore.": "पुनर्स्थापित करने के लिए कोई खरीदारी नहीं मिली।",
"Failed to restore purchases.": "खरीदारी पुनर्स्थापित करने में विफल।",
"Failed to manage subscription.": "सदस्यता प्रबंधित करने में विफल।",
"Failed to load subscription plans.": "सदस्यता योजनाएँ लोड करने में विफल।",
"year": "वर्ष",
"Failed to create checkout session": "चेकआउट सत्र बनाने में विफल",
"Storage": "भंडारण",
"Terms of Service": "सेवा की शर्तें",
"Privacy Policy": "गोपनीयता नीति",
"Disable Double Click": "डबल क्लिक अक्षम करें",
"TTS not supported for this document": "TTS इस दस्तावेज़ के लिए समर्थित नहीं है",
"Reset Password": "पासवर्ड रीसेट करें",
"Show Reading Progress": "पढ़ने की प्रगति दिखाएं",
"Reading Progress Style": "पढ़ने की प्रगति शैली",
"Page Number": "पृष्ठ संख्या",
"Percentage": "प्रतिशत",
"Deleted local copy of the book: {{title}}": "पुस्तक की स्थानीय प्रति हटाई गई: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "पुस्तक का क्लाउड बैकअप हटाने में विफल: {{title}}",
"Failed to delete local copy of the book: {{title}}": "पुस्तक की स्थानीय प्रति हटाने में विफल: {{title}}",
"Are you sure to delete the local copy of the selected book?": "क्या आप सुनिश्चित हैं कि आप चयनित पुस्तक की स्थानीय प्रति हटाना चाहते हैं?",
"Remove from Cloud & Device": "क्लाउड और डिवाइस से हटाएँ",
"Remove from Cloud Only": "केवल क्लाउड से हटाएँ",
"Remove from Device Only": "केवल डिवाइस से हटाएँ",
"Disconnected": "अविचलित",
"KOReader Sync Settings": "KOReader सिंक सेटिंग्स",
"Sync Strategy": "सिंक रणनीति",
"Ask on conflict": "संघर्ष पर पूछें",
"Always use latest": "हमेशा नवीनतम का उपयोग करें",
"Send changes only": "केवल परिवर्तन भेजें",
"Receive changes only": "केवल परिवर्तन प्राप्त करें",
"Checksum Method": "चेकसम विधि",
"File Content (recommended)": "फाइल सामग्री (अनुशंसित)",
"File Name": "फाइल नाम",
"Device Name": "डिवाइस नाम",
"Connect to your KOReader Sync server.": "अपने KOReader सिंक सर्वर से कनेक्ट करें।",
"Server URL": "सर्वर यूआरएल",
"Username": "उपयोगकर्ता नाम",
"Your Username": "आपका उपयोगकर्ता नाम",
"Password": "पासवर्ड",
"Connect": "कनेक्ट करें",
"KOReader Sync": "KOReader सिंक",
"Sync Conflict": "सिंक संघर्ष",
"Sync reading progress from \"{{deviceName}}\"?": "क्या आप \"{{deviceName}}\" से पढ़ने की प्रगति को सिंक करना चाहते हैं?",
"another device": "दूसरा डिवाइस",
"Local Progress": "स्थानीय प्रगति",
"Remote Progress": "दूरस्थ प्रगति",
"Page {{page}} of {{total}} ({{percentage}}%)": "पृष्ठ {{page}} कुल {{total}} ({{percentage}}%)",
"Current position": "वर्तमान स्थिति",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "लगभग पृष्ठ {{page}} कुल {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "लगभग {{percentage}}%",
"Failed to connect": "कनेक्ट करने में विफल",
"Sync Server Connected": "सिंक सर्वर कनेक्टेड",
"Sync as {{userDisplayName}}": "सिंक के रूप में {{userDisplayName}}",
"Custom Fonts": "कस्टम फ़ॉन्ट",
"Cancel Delete": "डिलीट रद्द करें",
"Import Font": "फ़ॉन्ट आयात करें",
"Delete Font": "फ़ॉन्ट डिलीट करें",
"Tips": "सुझाव",
"Custom fonts can be selected from the Font Face menu": "कस्टम फ़ॉन्ट को फ़ॉन्ट फेस मेनू से चुना जा सकता है",
"Manage Custom Fonts": "कस्टम फ़ॉन्ट प्रबंधन",
"Select Files": "फ़ाइलें चुनें",
"Select Image": "छवि चुनें",
"Select Video": "वीडियो चुनें",
"Select Audio": "ऑडियो चुनें",
"Select Fonts": "फ़ॉन्ट चुनें",
"Supported font formats: .ttf, .otf, .woff, .woff2": "समर्थित फ़ॉन्ट प्रारूप: .ttf, .otf, .woff, .woff2",
"Push Progress": "पुश प्रगति",
"Pull Progress": "पुल प्रगति",
"Previous Paragraph": "पिछला पैराग्राफ",
"Previous Sentence": "पिछला वाक्य",
"Pause": "रोकें",
"Play": "चलाएं",
"Next Sentence": "अगला वाक्य",
"Next Paragraph": "अगला पैराग्राफ",
"Separate Cover Page": "अलग कवर पृष्ठ",
"Resize Notebook": "नोटबुक का आकार बदलें",
"Resize Sidebar": "साइडबार का आकार बदलें",
"Get Help from the Readest Community": "Readest समुदाय से मदद लें",
"Remove cover image": "कवर इमेज हटाएं",
"Bookshelf": "पुस्तक शेल्फ",
"View Menu": "मेनू देखें",
"Settings Menu": "सेटिंग्स मेनू",
"View account details and quota": "खाता विवरण और कोटा देखें",
"Library Header": "पुस्तकालय शीर्षक",
"Book Content": "पुस्तक की सामग्री",
"Footer Bar": "फुटर बार",
"Header Bar": "हेडर बार",
"View Options": "देखने के विकल्प",
"Book Menu": "पुस्तक मेनू",
"Search Options": "खोज विकल्प",
"Close": "बंद करें",
"Delete Book Options": "पुस्तक हटाने के विकल्प",
"ON": "चालू",
"OFF": "बंद",
"Reading Progress": "पढ़ने की प्रगति",
"Page Margin": "पृष्ठ का मार्जिन",
"Remove Bookmark": "मार्कर हटाएं",
"Add Bookmark": "मार्कर जोड़ें",
"Books Content": "पुस्तकों की सामग्री",
"Jump to Location": "स्थान पर जाएं",
"Unpin Notebook": "नोटबुक अनपिन करें",
"Pin Notebook": "नोटबुक पिन करें",
"Hide Search Bar": "खोज बार छिपाएं",
"Show Search Bar": "खोज बार दिखाएं",
"On {{current}} of {{total}} page": "पृष्ठ {{current}} कुल {{total}} पर",
"Section Title": "अनुभाग शीर्षक",
"Decrease": "कम करें",
"Increase": "बढ़ाएं",
"Settings Panels": "सेटिंग्स पैनल",
"Settings": "सेटिंग्स",
"Unpin Sidebar": "साइडबार अनपिन करें",
"Pin Sidebar": "साइडबार पिन करें",
"Toggle Sidebar": "साइडबार टॉगल करें",
"Toggle Translation": "अनुवाद टॉगल करें",
"Translation Disabled": "अनुवाद अक्षम",
"Minimize": "न्यूनतम करें",
"Maximize or Restore": "अधिकतम या पुनर्स्थापित करें",
"Exit Parallel Read": "पैरालल रीड से बाहर निकलें",
"Enter Parallel Read": "पैरालल रीड में प्रवेश करें",
"Zoom Level": "ज़ूम स्तर",
"Zoom Out": "ज़ूम आउट",
"Reset Zoom": "ज़ूम रीसेट करें",
"Zoom In": "ज़ूम इन",
"Zoom Mode": "ज़ूम मोड",
"Single Page": "एकल पृष्ठ",
"Auto Spread": "स्वचालित फैलाव",
"Fit Page": "पृष्ठ में फिट करें",
"Fit Width": "चौड़ाई में फिट करें",
"Failed to select directory": "निर्देशिका का चयन करने में विफल",
"The new data directory must be different from the current one.": "नया डेटा निर्देशिका वर्तमान से भिन्न होना चाहिए।",
"Migration failed: {{error}}": "माइग्रेशन विफल: {{error}}",
"Change Data Location": "डेटा स्थान बदलें",
"Current Data Location": "वर्तमान डेटा स्थान",
"Total size: {{size}}": "कुल आकार: {{size}}",
"Calculating file info...": "फ़ाइल जानकारी की गणना कर रहे हैं...",
"New Data Location": "नया डेटा स्थान",
"Choose Different Folder": "विभिन्न फ़ोल्डर चुनें",
"Choose New Folder": "नया फ़ोल्डर चुनें",
"Migrating data...": "डेटा माइग्रेट कर रहे हैं...",
"Copying: {{file}}": "कॉपी कर रहे हैं: {{file}}",
"{{current}} of {{total}} files": "{{current}} में से {{total}} फ़ाइलें",
"Migration completed successfully!": "माइग्रेशन सफलतापूर्वक पूरा हुआ!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "आपका डेटा नए स्थान पर स्थानांतरित कर दिया गया है। कृपया प्रक्रिया को पूरा करने के लिए एप्लिकेशन को पुनरारंभ करें।",
"Migration failed": "माइग्रेशन विफल",
"Important Notice": "महत्वपूर्ण सूचना",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "यह आपके सभी ऐप डेटा को नए स्थान पर स्थानांतरित कर देगा। सुनिश्चित करें कि गंतव्य में पर्याप्त खाली स्थान है।",
"Restart App": "एप्लिकेशन पुनरारंभ करें",
"Start Migration": "माइग्रेशन प्रारंभ करें",
"Advanced Settings": "उन्नत सेटिंग्स",
"File count: {{size}}": "फ़ाइलों की संख्या: {{size}}",
"Background Read Aloud": "पृष्ठभूमि में वाचन",
"Ready to read aloud": "उच्च स्वर में पढ़ने के लिए तैयार",
"Read Aloud": "उच्च स्वर में पढ़ें",
"Screen Brightness": "स्क्रीन ब्राइटनेस",
"Background Image": "पृष्ठभूमि छवि",
"Import Image": "छवि आयात करें",
"Opacity": "अस्पष्टता",
"Size": "आकार",
"Cover": "कवर",
"Contain": "समाहित करें",
"{{number}} pages left in chapter": "<1>इस अध्याय में </1><0>{{number}}</0><1> पृष्ठ शेष हैं</1>",
"Device": "डिवाइस",
"E-Ink Mode": "ई-इंक मोड",
"Highlight Colors": "हाइलाइट रंग",
"Pagination": "पृष्ठांकन",
"Disable Double Tap": "डबल टैप अक्षम करें",
"Tap to Paginate": "पृष्ठांकन के लिए टैप करें",
"Click to Paginate": "पृष्ठांकन के लिए क्लिक करें",
"Tap Both Sides": "दोनों पक्षों पर टैप करें",
"Click Both Sides": "दोनों पक्षों पर क्लिक करें",
"Swap Tap Sides": "स्वैप टैप साइड्स",
"Swap Click Sides": "स्वैप क्लिक साइड्स",
"Source and Translated": "स्रोत और अनुवादित",
"Translated Only": "केवल अनुवादित",
"Source Only": "केवल स्रोत",
"TTS Text": "TTS टेक्स्ट",
"The book file is corrupted": "पुस्तक फ़ाइल भ्रष्ट है।",
"The book file is empty": "पुस्तक फ़ाइल खाली है।",
"Failed to open the book file": "पुस्तक फ़ाइल खोलने में विफल।",
"On-Demand Purchase": "आवश्यकता के अनुसार खरीदारी",
"Full Customization": "पूर्ण अनुकूलन",
"Lifetime Plan": "जीवनकाल योजना",
"One-Time Payment": "एक बार का भुगतान",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "सभी उपकरणों पर विशिष्ट सुविधाओं तक जीवनकाल पहुंच का आनंद लेने के लिए एक बार का भुगतान करें। जब आपको उनकी आवश्यकता हो, तो केवल विशिष्ट सुविधाओं या सेवाओं को खरीदें।",
"Expand Cloud Sync Storage": "क्लाउड सिंक स्टोरेज का विस्तार करें",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "एक बार के खरीदारी के साथ अपने क्लाउड स्टोरेज का विस्तार करें। प्रत्येक अतिरिक्त खरीदारी अधिक स्थान जोड़ती है।",
"Unlock All Customization Options": "सभी अनुकूलन विकल्प अनलॉक करें",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "अतिरिक्त थीम, फ़ॉन्ट, लेआउट विकल्प और पढ़ने के लिए, अनुवादक, क्लाउड स्टोरेज सेवाएँ अनलॉक करें।",
"Purchase Successful!": "खरीदारी सफल!",
"lifetime": "जीवनकाल",
"Thank you for your purchase! Your payment has been processed successfully.": "आपकी खरीदारी के लिए धन्यवाद! आपका भुगतान सफलतापूर्वक संसाधित हो गया है।",
"Order ID:": "ऑर्डर आईडी:",
"TTS Highlighting": "TTS हाइलाइटिंग",
"Style": "शैली",
"Underline": "रेखांकित",
"Strikethrough": "रेखांकित करें",
"Squiggly": "स्क्विगली",
"Outline": "आउटलाइन",
"Save Current Color": "वर्तमान रंग सहेजें",
"Quick Colors": "त्वरित रंग",
"Highlighter": "हाइलाइटर",
"Save Book Cover": "बुक कवर सहेजें",
"Auto-save last book cover": "अंतिम पुस्तक कवर को स्वचालित रूप से सहेजें",
"Back": "वापस",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "पुष्टिकरण ईमेल भेज दिया गया है! कृपया परिवर्तन की पुष्टि करने के लिए अपना पुराना और नया ईमेल पता जांचें।",
"Failed to update email": "ईमेल अपडेट करने में विफल",
"New Email": "नया ईमेल",
"Your new email": "आपका नया ईमेल",
"Updating email ...": "ईमेल अपडेट किया जा रहा है ...",
"Update email": "ईमेल अपडेट करें",
"Current email": "वर्तमान ईमेल",
"Update Email": "ईमेल अपडेट करें",
"All": "सभी",
"Unable to open book": "पुस्तक खोलने में असमर्थ",
"Punctuation": "विराम चिह्न",
"Replace Quotation Marks": "उद्धरण चिह्न बदलें",
"Enabled only in vertical layout.": "केवल ऊर्ध्वाधर लेआउट में सक्षम।",
"No Conversion": "कोई रूपांतरण नहीं",
"Simplified to Traditional": "सरलीकृत → पारंपरिक",
"Traditional to Simplified": "पारंपरिक → सरलीकृत",
"Simplified to Traditional (Taiwan)": "सरलीकृत → पारंपरिक (ताइवान)",
"Simplified to Traditional (Hong Kong)": "सरलीकृत → पारंपरिक (हांगकांग)",
"Simplified to Traditional (Taiwan), with phrases": "सरलीकृत → पारंपरिक (ताइवान • वाक्यांश)",
"Traditional (Taiwan) to Simplified": "पारंपरिक (ताइवान) → सरलीकृत",
"Traditional (Hong Kong) to Simplified": "पारंपरिक (हांगकांग) → सरलीकृत",
"Traditional (Taiwan) to Simplified, with phrases": "पारंपरिक (ताइवान • वाक्यांश) → सरलीकृत",
"Convert Simplified and Traditional Chinese": "सरलीकृत/पारंपरिक चीनी रूपांतरण",
"Convert Mode": "रूपांतरण मोड",
"Failed to auto-save book cover for lock screen: {{error}}": "लॉक स्क्रीन के लिए पुस्तक कवर स्वचालित रूप से सहेजने में विफल: {{error}}",
"Download from Cloud": "क्लाउड से डाउनलोड करें",
"Upload to Cloud": "क्लाउड पर अपलोड करें",
"Clear Custom Fonts": "कस्टम फ़ॉन्ट साफ़ करें",
"Columns": "कॉलम",
"OPDS Catalogs": "OPDS कैटलॉग",
"Adding LAN addresses is not supported in the web app version.": "वेब ऐप संस्करण में LAN पता जोड़ना समर्थित नहीं है।",
"Invalid OPDS catalog. Please check the URL.": "अमान्य OPDS कैटलॉग। कृपया URL जांचें।",
"Browse and download books from online catalogs": "ऑनलाइन कैटलॉग से किताबें ब्राउज़ और डाउनलोड करें",
"My Catalogs": "मेरे कैटलॉग",
"Add Catalog": "कैटलॉग जोड़ें",
"No catalogs yet": "अभी कोई कैटलॉग नहीं",
"Add your first OPDS catalog to start browsing books": "किताबें ब्राउज़ करने के लिए अपना पहला OPDS कैटलॉग जोड़ें",
"Add Your First Catalog": "अपना पहला कैटलॉग जोड़ें",
"Browse": "ब्राउज़",
"Popular Catalogs": "लोकप्रिय कैटलॉग",
"Add": "जोड़ें",
"Add OPDS Catalog": "OPDS कैटलॉग जोड़ें",
"Catalog Name": "कैटलॉग नाम",
"My Calibre Library": "मेरी Calibre लाइब्रेरी",
"OPDS URL": "OPDS URL",
"Username (optional)": "यूज़रनेम (वैकल्पिक)",
"Password (optional)": "पासवर्ड (वैकल्पिक)",
"Description (optional)": "विवरण (वैकल्पिक)",
"A brief description of this catalog": "इस कैटलॉग का संक्षिप्त विवरण",
"Validating...": "मान्य किया जा रहा है...",
"View All": "सभी देखें",
"Forward": "आगे",
"Home": "होम",
"{{count}} items_one": "{{count}} आइटम",
"{{count}} items_other": "{{count}} आइटम",
"Download completed": "डाउनलोड पूरा हुआ",
"Download failed": "डाउनलोड विफल हुआ",
"Open Access": "ओपन एक्सेस",
"Borrow": "उधार लें",
"Buy": "खरीदें",
"Subscribe": "सदस्यता लें",
"Sample": "नमूना",
"Download": "डाउनलोड",
"Open & Read": "खोलें और पढ़ें",
"Tags": "टैग",
"Tag": "टैग",
"First": "पहला",
"Previous": "पिछला",
"Next": "अगला",
"Last": "अंतिम",
"Cannot Load Page": "पृष्ठ लोड नहीं किया जा सका",
"An error occurred": "एक त्रुटि हुई",
"Online Library": "ऑनलाइन लाइब्रेरी",
"URL must start with http:// or https://": "URL http:// या https:// से शुरू होना चाहिए",
"Title, Author, Tag, etc...": "शीर्षक, लेखक, टैग, आदि...",
"Query": "प्रश्न",
"Subject": "विषय",
"Enter {{terms}}": "{{terms}} दर्ज करें",
"No search results found": "कोई खोज परिणाम नहीं मिला",
"Failed to load OPDS feed: {{status}} {{statusText}}": "OPDS फ़ीड लोड करने में विफल: {{status}} {{statusText}}",
"Search in {{title}}": "{{title}} में खोजें",
"Manage Storage": "स्टोरेज प्रबंधित करें",
"Failed to load files": "फ़ाइलें लोड करने में विफल",
"Deleted {{count}} file(s)_one": "{{count}} फ़ाइल हटाई गई",
"Deleted {{count}} file(s)_other": "{{count}} फ़ाइलें हटाई गईं",
"Failed to delete {{count}} file(s)_one": "{{count}} फ़ाइल हटाने में विफल",
"Failed to delete {{count}} file(s)_other": "{{count}} फ़ाइलें हटाने में विफल",
"Failed to delete files": "फ़ाइलें हटाने में विफल",
"Total Files": "कुल फ़ाइलें",
"Total Size": "कुल आकार",
"Quota": "कोटा",
"Used": "उपयोग किया गया",
"Files": "फ़ाइलें",
"Search files...": "फ़ाइलें खोजें...",
"Newest First": "नवीनतम पहले",
"Oldest First": "सबसे पुराने पहले",
"Largest First": "सबसे बड़ी पहले",
"Smallest First": "सबसे छोटी पहले",
"Name A-Z": "नाम A-Z",
"Name Z-A": "नाम Z-A",
"{{count}} selected_one": "{{count}} चयनित",
"{{count}} selected_other": "{{count}} चयनित",
"Delete Selected": "चयनित हटाएँ",
"Created": "बनाई गई",
"No files found": "कोई फ़ाइल नहीं मिली",
"No files uploaded yet": "अभी तक कोई फ़ाइल अपलोड नहीं की गई",
"files": "फ़ाइलें",
"Page {{current}} of {{total}}": "पृष्ठ {{current}} / {{total}}",
"Are you sure to delete {{count}} selected file(s)?_one": "क्या आप वाकई {{count}} चयनित फ़ाइल हटाना चाहते हैं?",
"Are you sure to delete {{count}} selected file(s)?_other": "क्या आप वाकई {{count}} चयनित फ़ाइलें हटाना चाहते हैं?",
"Cloud Storage Usage": "क्लाउड स्टोरेज उपयोग",
"Rename Group": "समूह का नाम बदलें",
"From Directory": "निर्देशिका से",
"Successfully imported {{count}} book(s)_one": "सफलतापूर्वक 1 पुस्तक आयात की गई",
"Successfully imported {{count}} book(s)_other": "सफलतापूर्वक {{count}} पुस्तकों का आयात किया गया",
"Count": "गणना",
"Start Page": "प्रारंभ पृष्ठ",
"Search in OPDS Catalog...": "OPDS कैटलॉग में खोजें...",
"Please log in to use advanced TTS features": "उन्नत TTS सुविधाओं का उपयोग करने के लिए कृपया लॉग इन करें।",
"Word limit of 30 words exceeded.": "30 शब्दों की सीमा पार हो गई है।",
"Proofread": "प्रूफ़रीड",
"Current selection": "वर्तमान चयन",
"All occurrences in this book": "इस पुस्तक में सभी स्थान",
"All occurrences in your library": "आपकी लाइब्रेरी में सभी स्थान",
"Selected text:": "चयनित पाठ:",
"Replace with:": "से बदलें:",
"Enter text...": "पाठ दर्ज करें…",
"Case sensitive:": "अक्षर संवेदनशील:",
"Scope:": "क्षेत्र:",
"Selection": "चयन",
"Library": "लाइब्रेरी",
"Yes": "हाँ",
"No": "नहीं",
"Proofread Replacement Rules": "प्रूफ़रीड प्रतिस्थापन नियम",
"Selected Text Rules": "चयनित पाठ के नियम",
"No selected text replacement rules": "चयनित पाठ के लिए कोई प्रतिस्थापन नियम नहीं हैं",
"Book Specific Rules": "पुस्तक-विशिष्ट नियम",
"No book-level replacement rules": "पुस्तक स्तर पर कोई प्रतिस्थापन नियम नहीं हैं",
"Disable Quick Action": "त्वरित क्रिया अक्षम करें",
"Enable Quick Action on Selection": "चयन पर त्वरित क्रिया सक्षम करें",
"None": "कोई नहीं",
"Annotation Tools": "टिप्पणी उपकरण",
"Enable Quick Actions": "त्वरित क्रियाएँ सक्षम करें",
"Quick Action": "त्वरित क्रिया",
"Copy to Notebook": "नोटबुक में कॉपी करें",
"Copy text after selection": "पाठ कॉपी करें चयन के बाद",
"Highlight text after selection": "चयन के बाद पाठ हाइलाइट करें",
"Annotate text after selection": "चयन के बाद पाठ पर टिप्पणी करें",
"Search text after selection": "चयन के बाद पाठ खोजें",
"Look up text in dictionary after selection": "चयन के बाद शब्दकोश में पाठ देखें",
"Look up text in Wikipedia after selection": "चयन के बाद विकिपीडिया में पाठ देखें",
"Translate text after selection": "चयन के बाद पाठ का अनुवाद करें",
"Read text aloud after selection": "चयन के बाद पाठ को जोर से पढ़ें",
"Proofread text after selection": "चयन के बाद पाठ को प्रूफरीड करें",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} सक्रिय, {{pendingCount}} लंबित",
"{{failedCount}} failed": "{{failedCount}} विफल",
"Waiting...": "प्रतीक्षा कर रहे हैं...",
"Failed": "विफल",
"Completed": "पूर्ण",
"Cancelled": "रद्द",
"Retry": "पुनः प्रयास करें",
"Active": "सक्रिय",
"Transfer Queue": "स्थानांतरण कतार",
"Upload All": "सभी अपलोड करें",
"Download All": "सभी डाउनलोड करें",
"Resume Transfers": "स्थानांतरण जारी रखें",
"Pause Transfers": "स्थानांतरण रोकें",
"Pending": "लंबित",
"No transfers": "कोई स्थानांतरण नहीं",
"Retry All": "सभी पुनः प्रयास करें",
"Clear Completed": "पूर्ण साफ़ करें",
"Clear Failed": "विफल साफ़ करें",
"Upload queued: {{title}}": "अपलोड कतार में: {{title}}",
"Download queued: {{title}}": "डाउनलोड कतार में: {{title}}",
"Book not found in library": "पुस्तकालय में पुस्तक नहीं मिली",
"Unknown error": "अज्ञात त्रुटि",
"Please log in to continue": "जारी रखने के लिए लॉगिन करें",
"Cloud File Transfers": "क्लाउड फ़ाइल स्थानांतरण",
"Show Search Results": "खोज परिणाम दिखाएं",
"Search results for '{{term}}'": "'{{term}}' के परिणाम",
"Close Search": "खोज बंद करें",
"Previous Result": "पिछला परिणाम",
"Next Result": "अगला परिणाम",
"Bookmarks": "बुकमार्क",
"Annotations": "टिप्पणियाँ",
"Show Results": "परिणाम दिखाएं",
"Clear search": "खोज साफ़ करें",
"Clear search history": "खोज इतिहास साफ़ करें",
"Tap to Toggle Footer": "फुटर टॉगल करने के लिए टैप करें",
"Show Current Time": "वर्तमान समय दिखाएं",
"Use 24 Hour Clock": "24 घंटे की घड़ी का उपयोग करें",
"Show Current Battery Status": "वर्तमान बैटरी स्थिति दिखाएं",
"Exported successfully": "सफलतापूर्वक निर्यात किया गया",
"Book exported successfully.": "पुस्तक सफलतापूर्वक निर्यात की गई।",
"Failed to export the book.": "पुस्तक निर्यात करने में विफल।",
"Export Book": "पुस्तक निर्यात करें",
"Whole word:": "पूरा शब्द:",
"Error": "त्रुटि",
"Unable to load the article. Try searching directly on {{link}}.": "लेख लोड करने में असमर्थ। सीधे {{link}} पर खोजने का प्रयास करें।",
"Unable to load the word. Try searching directly on {{link}}.": "शब्द लोड करने में असमर्थ। सीधे {{link}} पर खोजने का प्रयास करें।",
"Date Published": "प्रकाशन तिथि",
"Only for TTS:": "केवल TTS के लिए:",
"Uploaded": "अपलोड किया गया",
"Downloaded": "डाउनलोड किया गया",
"Deleted": "हटाया गया",
"Note:": "नोट:",
"Time:": "समय:",
"Format Options": "प्रारूप विकल्प",
"Export Date": "निर्यात तिथि",
"Chapter Titles": "अध्याय शीर्षक",
"Chapter Separator": "अध्याय विभाजक",
"Highlights": "हाइलाइट्स",
"Note Date": "नोट तिथि",
"Advanced": "उन्नत",
"Hide": "छिपाएं",
"Show": "दिखाएं",
"Use Custom Template": "कस्टम टेम्पलेट उपयोग करें",
"Export Template": "निर्यात टेम्पलेट",
"Template Syntax:": "टेम्पलेट सिंटैक्स:",
"Insert value": "मान डालें",
"Format date (locale)": "तिथि फ़ॉर्मेट करें (स्थानीय)",
"Format date (custom)": "तिथि फ़ॉर्मेट करें (कस्टम)",
"Conditional": "सशर्त",
"Loop": "लूप",
"Available Variables:": "उपलब्ध चर:",
"Book title": "पुस्तक शीर्षक",
"Book author": "पुस्तक लेखक",
"Export date": "निर्यात तिथि",
"Array of chapters": "अध्यायों की सूची",
"Chapter title": "अध्याय शीर्षक",
"Array of annotations": "एनोटेशन की सूची",
"Highlighted text": "हाइलाइट किया गया पाठ",
"Annotation note": "एनोटेशन नोट",
"Date Format Tokens:": "तिथि प्रारूप टोकन:",
"Year (4 digits)": "वर्ष (4 अंक)",
"Month (01-12)": "माह (01-12)",
"Day (01-31)": "दिन (01-31)",
"Hour (00-23)": "घंटा (00-23)",
"Minute (00-59)": "मिनट (00-59)",
"Second (00-59)": "सेकंड (00-59)",
"Show Source": "स्रोत दिखाएं",
"No content to preview": "पूर्वावलोकन के लिए कोई सामग्री नहीं",
"Export": "निर्यात करें",
"Set Timeout": "टाइमआउट सेट करें",
"Select Voice": "आवाज़ चुनें",
"Toggle Sticky Bottom TTS Bar": "स्थिर TTS बार टॉगल करें",
"Display what I'm reading on Discord": "Discord पर पढ़ रही किताब दिखाएं",
"Show on Discord": "Discord पर दिखाएं",
"Instant {{action}}": "तत्काल {{action}}",
"Instant {{action}} Disabled": "तत्काल {{action}} अक्षम",
"Annotation": "टिप्पणी",
"Reset Template": "टेम्पलेट रीसेट करें",
"Annotation style": "एनोटेशन शैली",
"Annotation color": "एनोटेशन रंग",
"Annotation time": "एनोटेशन समय",
"AI": "AI",
"Are you sure you want to re-index this book?": "क्या आप वाकई इस पुस्तक को फिर से इंडेक्स करना चाहते हैं?",
"Enable AI in Settings": "सेटिंग्स में AI सक्षम करें",
"Index This Book": "इस पुस्तक को इंडेक्स करें",
"Enable AI search and chat for this book": "इस पुस्तक के लिए AI खोज और चैट सक्षम करें",
"Start Indexing": "इंडेक्सिंग शुरू करें",
"Indexing book...": "पुस्तक इंडेक्स हो रही है...",
"Preparing...": "तैयारी हो रही है...",
"Delete this conversation?": "इस वार्तालाप को हटाएं?",
"No conversations yet": "अभी तक कोई वार्तालाप नहीं",
"Start a new chat to ask questions about this book": "इस पुस्तक के बारे में प्रश्न पूछने के लिए नई चैट शुरू करें",
"Rename": "नाम बदलें",
"New Chat": "नई चैट",
"Chat": "चैट",
"Please enter a model ID": "कृपया मॉडल ID दर्ज करें",
"Model not available or invalid": "मॉडल उपलब्ध नहीं या अमान्य है",
"Failed to validate model": "मॉडल सत्यापित करने में विफल",
"Couldn't connect to Ollama. Is it running?": "Ollama से कनेक्ट नहीं हो सका। क्या यह चल रहा है?",
"Invalid API key or connection failed": "अमान्य API कुंजी या कनेक्शन विफल",
"Connection failed": "कनेक्शन विफल",
"AI Assistant": "AI सहायक",
"Enable AI Assistant": "AI सहायक सक्षम करें",
"Provider": "प्रदाता",
"Ollama (Local)": "Ollama (स्थानीय)",
"AI Gateway (Cloud)": "AI गेटवे (क्लाउड)",
"Ollama Configuration": "Ollama कॉन्फ़िगरेशन",
"Refresh Models": "मॉडल रीफ्रेश करें",
"AI Model": "AI मॉडल",
"No models detected": "कोई मॉडल नहीं मिला",
"AI Gateway Configuration": "AI गेटवे कॉन्फ़िगरेशन",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "उच्च-गुणवत्ता, किफायती AI मॉडल के चयन में से चुनें। आप नीचे \"कस्टम मॉडल\" का चयन करके अपना मॉडल भी उपयोग कर सकते हैं।",
"API Key": "API कुंजी",
"Get Key": "कुंजी प्राप्त करें",
"Model": "मॉडल",
"Custom Model...": "कस्टम मॉडल...",
"Custom Model ID": "कस्टम मॉडल ID",
"Validate": "सत्यापित करें",
"Model available": "मॉडल उपलब्ध",
"Connection": "कनेक्शन",
"Test Connection": "कनेक्शन परीक्षण",
"Connected": "कनेक्टेड",
"Custom Colors": "कस्टम रंग",
"Color E-Ink Mode": "कलर ई-इंक मोड",
"Reading Ruler": "पठन रूलर",
"Enable Reading Ruler": "पठन रूलर सक्षम करें",
"Lines to Highlight": "हाइलाइट करने के लिए पंक्तियाँ",
"Ruler Color": "रूलर का रंग",
"Command Palette": "कमांड पैलेट",
"Search settings and actions...": "सेटिंग और क्रियाएं खोजें...",
"No results found for": "के लिए कोई परिणाम नहीं मिला",
"Type to search settings and actions": "सेटिंग और क्रियाएं खोजने के लिए टाइप करें",
"Recent": "हालिया",
"navigate": "नेविगेट",
"select": "चुनें",
"close": "बंद करें",
"Search Settings": "सेटिंग खोजें",
"Page Margins": "पेज मार्जिन",
"AI Provider": "AI प्रदाता",
"Ollama URL": "Ollama URL",
"Ollama Model": "Ollama मॉडल",
"AI Gateway Model": "AI गेटवे मॉडल",
"Actions": "क्रियाएं",
"Navigation": "नेविगेशन",
"Set status for {{count}} book(s)_one": "{{count}} किताब की स्थिति सेट करें",
"Set status for {{count}} book(s)_other": "{{count}} किताबों की स्थिति सेट करें",
"Mark as Unread": "अपठित के रूप में चिह्नित करें",
"Mark as Finished": "समाप्त के रूप में चिह्नित करें",
"Finished": "समाप्त",
"Unread": "अपठित",
"Clear Status": "स्थिति साफ़ करें",
"Status": "स्थिति",
"Loading": "लोड हो रहा है...",
"Exit Paragraph Mode": "पैराग्राफ मोड से बाहर निकलें",
"Paragraph Mode": "पैराग्राफ मोड",
"Embedding Model": "एंबेडिंग मॉडल",
"{{count}} book(s) synced_one": "{{count}} पुस्तक सिंक की गई",
"{{count}} book(s) synced_other": "{{count}} पुस्तकें सिंक की गईं",
"Unable to start RSVP": "RSVP शुरू करने में असमर्थ",
"RSVP not supported for PDF": "PDF के लिए RSVP समर्थित नहीं है",
"Select Chapter": "अध्याय चुनें",
"Context": "संदर्भ",
"Ready": "तैयार",
"Chapter Progress": "अध्याय प्रगति",
"words": "शब्द",
"{{time}} left": "{{time}} शेष",
"Reading progress": "पठन प्रगति",
"Skip back 15 words": "15 शब्द पीछे",
"Back 15 words (Shift+Left)": "15 शब्द पीछे (Shift+Left)",
"Pause (Space)": "विराम (Space)",
"Play (Space)": "चलाएं (Space)",
"Skip forward 15 words": "15 शब्द आगे",
"Forward 15 words (Shift+Right)": "15 शब्द आगे (Shift+Right)",
"Decrease speed": "गति कम करें",
"Slower (Left/Down)": "धीमी (Left/Down)",
"Increase speed": "गति बढ़ाएं",
"Faster (Right/Up)": "तेज़ (Right/Up)",
"Start RSVP Reading": "RSVP पठन शुरू करें",
"Choose where to start reading": "चुनें कि कहाँ से पढ़ना शुरू करना है",
"From Chapter Start": "अध्याय के आरंभ से",
"Start reading from the beginning of the chapter": "अध्याय की शुरुआत से पढ़ना शुरू करें",
"Resume": "फिर से शुरू करें",
"Continue from where you left off": "वहीं से जारी रखें जहाँ आपने छोड़ा था",
"From Current Page": "वर्तमान पृष्ठ से",
"Start from where you are currently reading": "जहाँ आप अभी पढ़ रहे हैं वहीं से शुरू करें",
"From Selection": "चयन से",
"Speed Reading Mode": "त्वरित पठन मोड",
"Scroll left": "बाएं स्क्रॉल करें",
"Scroll right": "दाएं स्क्रॉल करें",
"Library Sync Progress": "पुस्तकालय सिंक प्रगति",
"Back to library": "लाइब्रेरी पर वापस जाएं",
"Group by...": "इसके द्वारा समूहबद्ध करें...",
"Export as Plain Text": "प्लेन टेक्स्ट के रूप में एक्सपोर्ट करें",
"Export as Markdown": "Markdown के रूप में एक्सपोर्ट करें",
"Show Page Navigation Buttons": "नेविगेशन बटन",
"Page {{number}}": "पृष्ठ {{number}}",
"highlight": "हाइलाइट",
"underline": "अंडरलाइन",
"squiggly": "टेढ़ी-मेढ़ी रेखा",
"red": "लाल",
"violet": "बैंगनी",
"blue": "नीला",
"green": "हरा",
"yellow": "पीला",
"Select {{style}} style": "{{style}} शैली चुनें",
"Select {{color}} color": "{{color}} रंग चुनें",
"Close Book": "किताब बंद करें",
"Speed Reading": "तीव्र पठन",
"Close Speed Reading": "तीव्र पठन बंद करें",
"Authors": "लेखक",
"Books": "पुस्तकें",
"Groups": "समूह",
"Back to TTS Location": "टीटीएस स्थान पर वापस जाएं",
"Metadata": "मेटाडाटा",
"Image viewer": "छवि दर्शक",
"Previous Image": "पिछली छवि",
"Next Image": "अगली छवि",
"Zoomed": "ज़ूम किया गया",
"Zoom level": "ज़ूम स्तर",
"Table viewer": "तालिका दर्शक",
"Unable to connect to Readwise. Please check your network connection.": "Readwise से कनेक्ट करने में असमर्थ। कृपया अपना नेटवर्क कनेक्शन जांचें।",
"Invalid Readwise access token": "अमान्य Readwise एक्सेस टोकन",
"Disconnected from Readwise": "Readwise से डिस्कनेक्ट हो गया",
"Never": "कभी नहीं",
"Readwise Settings": "Readwise सेटिंग्स",
"Connected to Readwise": "Readwise से जुड़ा हुआ",
"Last synced: {{time}}": "पिछला सिंक: {{time}}",
"Sync Enabled": "सिंक सक्षम",
"Disconnect": "डिस्कनेक्ट करें",
"Connect your Readwise account to sync highlights.": "हाइलाइट्स सिंक करने के लिए अपना Readwise खाता कनेक्ट करें।",
"Get your access token at": "अपना एक्सेस टोकन यहाँ प्राप्त करें",
"Access Token": "एक्सेस टोकन",
"Paste your Readwise access token": "अपना Readwise एक्सेस टोकन पेस्ट करें",
"Config": "कॉन्फिग",
"Readwise Sync": "Readwise सिंक",
"Push Highlights": "हाइलाइट्स भेजें",
"Highlights synced to Readwise": "हाइलाइट्स Readwise में सिंक हो गए",
"Readwise sync failed: no internet connection": "Readwise सिंक विफल रहा: कोई इंटरनेट कनेक्शन नहीं",
"Readwise sync failed: {{error}}": "Readwise सिंक विफल रहा: {{error}}",
"System Screen Brightness": "सिस्टम स्क्रीन चमक",
"Page:": "पृष्ठ:",
"Page: {{number}}": "पृष्ठ: {{number}}",
"Annotation page number": "व्याख्या पृष्ठ संख्या",
"Translating...": "अनुवाद हो रहा है...",
"Show Battery Percentage": "बैटरी प्रतिशत दिखाएं",
"Hide Scrollbar": "स्क्रॉलबार छुपाएँ",
"Skip to last reading position": "अंतिम पढ़ने की स्थिति पर जाएँ",
"Show context": "संदर्भ दिखाएँ",
"Hide context": "संदर्भ छुपाएँ",
"Decrease font size": "फ़ॉन्ट आकार घटाएँ",
"Increase font size": "फ़ॉन्ट आकार बढ़ाएँ",
"Focus": "फ़ोकस",
"Theme color": "थीम रंग",
"Import failed": "आयात विफल",
"Available Formatters:": "उपलब्ध फ़ॉर्मेटर:",
"Format date": "तारीख फ़ॉर्मेट करें",
"Markdown block quote (> per line)": "Markdown ब्लॉक कोट (> प्रति पंक्ति)",
"Newlines to <br>": "नई पंक्तियाँ <br> में",
"Change case": "केस बदलें",
"Trim whitespace": "रिक्त स्थान हटाएँ",
"Truncate to n characters": "n अक्षरों तक छोटा करें",
"Replace text": "टेक्स्ट बदलें",
"Fallback value": "फ़ॉलबैक मान",
"Get length": "लंबाई प्राप्त करें",
"First/last element": "पहला/अंतिम तत्व",
"Join array": "ऐरे जोड़ें",
"Backup failed: {{error}}": "बैकअप विफल: {{error}}",
"Select Backup": "बैकअप चुनें",
"Restore failed: {{error}}": "पुनर्स्थापना विफल: {{error}}",
"Backup & Restore": "बैकअप और पुनर्स्थापना",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "अपनी लाइब्रेरी का बैकअप बनाएं या पिछले बैकअप से पुनर्स्थापित करें। पुनर्स्थापना आपकी वर्तमान लाइब्रेरी के साथ मर्ज होगी।",
"Backup Library": "लाइब्रेरी बैकअप",
"Restore Library": "लाइब्रेरी पुनर्स्थापित करें",
"Creating backup...": "बैकअप बनाया जा रहा है...",
"Restoring library...": "लाइब्रेरी पुनर्स्थापित हो रही है...",
"{{current}} of {{total}} items": "{{current}} / {{total}} आइटम",
"Backup completed successfully!": "बैकअप सफलतापूर्वक पूर्ण!",
"Restore completed successfully!": "पुनर्स्थापना सफलतापूर्वक पूर्ण!",
"Your library has been saved to the selected location.": "आपकी लाइब्रेरी चयनित स्थान पर सहेजी गई है।",
"{{added}} books added, {{updated}} books updated.": "{{added}} पुस्तकें जोड़ी गईं, {{updated}} पुस्तकें अपडेट की गईं।",
"Operation failed": "ऑपरेशन विफल",
"Loading library...": "लाइब्रेरी लोड हो रही है...",
"{{count}} books refreshed_one": "{{count}} पुस्तक रिफ्रेश हुई",
"{{count}} books refreshed_other": "{{count}} पुस्तकें रिफ्रेश हुईं",
"Failed to refresh metadata": "मेटाडेटा रिफ्रेश विफल",
"Refresh Metadata": "मेटाडेटा रिफ्रेश करें",
"Keyboard Shortcuts": "कीबोर्ड शॉर्टकट",
"View all keyboard shortcuts": "सभी कीबोर्ड शॉर्टकट देखें",
"Switch Sidebar Tab": "साइडबार टैब बदलें",
"Toggle Notebook": "नोटबुक दिखाएँ/छुपाएँ",
"Search in Book": "पुस्तक में खोजें",
"Toggle Scroll Mode": "स्क्रॉल मोड टॉगल करें",
"Toggle Select Mode": "चयन मोड टॉगल करें",
"Toggle Bookmark": "बुकमार्क टॉगल करें",
"Toggle Text to Speech": "टेक्स्ट टू स्पीच टॉगल करें",
"Play / Pause TTS": "TTS चलाएँ / रोकें",
"Toggle Paragraph Mode": "अनुच्छेद मोड टॉगल करें",
"Highlight Selection": "चयन हाइलाइट करें",
"Underline Selection": "चयन अंडरलाइन करें",
"Annotate Selection": "चयन पर टिप्पणी करें",
"Search Selection": "चयन खोजें",
"Copy Selection": "चयन कॉपी करें",
"Translate Selection": "चयन का अनुवाद करें",
"Dictionary Lookup": "शब्दकोश में खोजें",
"Wikipedia Lookup": "विकिपीडिया पर खोजें",
"Read Aloud Selection": "चयन को ज़ोर से पढ़ें",
"Proofread Selection": "चयन की प्रूफरीडिंग करें",
"Open Settings": "सेटिंग्स खोलें",
"Open Command Palette": "कमांड पैलेट खोलें",
"Show Keyboard Shortcuts": "कीबोर्ड शॉर्टकट दिखाएँ",
"Open Books": "पुस्तकें खोलें",
"Toggle Fullscreen": "पूर्ण स्क्रीन टॉगल करें",
"Close Window": "विंडो बंद करें",
"Quit App": "ऐप से बाहर निकलें",
"Go Left / Previous Page": "बाएँ जाएँ / पिछला पृष्ठ",
"Go Right / Next Page": "दाएँ जाएँ / अगला पृष्ठ",
"Go Up": "ऊपर जाएँ",
"Go Down": "नीचे जाएँ",
"Previous Chapter": "पिछला अध्याय",
"Next Chapter": "अगला अध्याय",
"Scroll Half Page Down": "आधा पृष्ठ नीचे स्क्रॉल करें",
"Scroll Half Page Up": "आधा पृष्ठ ऊपर स्क्रॉल करें",
"Save Note": "नोट सहेजें",
"Single Section Scroll": "एकल अनुभाग स्क्रॉल",
"General": "सामान्य",
"Text to Speech": "पाठ से वाक्",
"Zoom": "ज़ूम",
"Window": "विंडो",
"Your Bookshelf": "आपकी किताबों की अलमारी",
"TTS": "पाठ से वाक्",
"Media Info": "मीडिया जानकारी",
"Update Frequency": "अपडेट आवृत्ति",
"Every Sentence": "हर वाक्य",
"Every Paragraph": "हर पैराग्राफ",
"Every Chapter": "हर अध्याय",
"TTS Media Info Update Frequency": "TTS मीडिया जानकारी अपडेट आवृत्ति",
"Select reading speed": "पढ़ने की गति चुनें",
"Drag to seek": "खोजने के लिए खींचें",
"Punctuation Delay": "विराम चिह्न विलंब",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "कृपया जारी रखने से पहले पुष्टि करें कि यह OPDS कनेक्शन वेब ऐप पर Readest सर्वर के माध्यम से प्रॉक्सी किया जाएगा।",
"Custom Headers": "कस्टम हेडर",
"Custom Headers (optional)": "कस्टम हेडर (वैकल्पिक)",
"Add one header per line using \"Header-Name: value\".": "\"Header-Name: value\" का उपयोग करके प्रति पंक्ति एक हेडर जोड़ें।",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "मैं समझता/समझती हूँ कि यह OPDS कनेक्शन वेब ऐप पर Readest सर्वर के माध्यम से प्रॉक्सी किया जाएगा। यदि मुझे इन क्रेडेंशियल या हेडर के साथ Readest पर भरोसा नहीं है, तो मुझे नेटिव ऐप का उपयोग करना चाहिए।",
"Unable to connect to Hardcover. Please check your network connection.": "Hardcover से कनेक्ट करने में असमर्थ। कृपया अपना नेटवर्क कनेक्शन जाँचें।",
"Invalid Hardcover API token": "अमान्य Hardcover API टोकन",
"Disconnected from Hardcover": "Hardcover से डिस्कनेक्ट हो गया",
"Hardcover Settings": "Hardcover सेटिंग्स",
"Connected to Hardcover": "Hardcover से कनेक्टेड",
"Connect your Hardcover account to sync reading progress and notes.": "पढ़ने की प्रगति और नोट्स सिंक करने के लिए अपना Hardcover खाता कनेक्ट करें।",
"Get your API token from hardcover.app → Settings → API.": "hardcover.app → सेटिंग्स → API से अपना API टोकन प्राप्त करें।",
"API Token": "API टोकन",
"Paste your Hardcover API token": "अपना Hardcover API टोकन पेस्ट करें",
"Hardcover sync enabled for this book": "इस पुस्तक के लिए Hardcover सिंक सक्षम",
"Hardcover sync disabled for this book": "इस पुस्तक के लिए Hardcover सिंक अक्षम",
"Hardcover Sync": "Hardcover सिंक",
"Enable for This Book": "इस पुस्तक के लिए सक्षम करें",
"Push Notes": "नोट्स भेजें",
"Enable Hardcover sync for this book first.": "पहले इस पुस्तक के लिए Hardcover सिंक सक्षम करें।",
"No annotations or excerpts to sync for this book.": "इस पुस्तक के लिए सिंक करने हेतु कोई एनोटेशन या अंश नहीं हैं।",
"Configure Hardcover in Settings first.": "पहले सेटिंग्स में Hardcover कॉन्फ़िगर करें।",
"No new Hardcover note changes to sync.": "सिंक करने के लिए कोई नया Hardcover नोट परिवर्तन नहीं है।",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover सिंक हुआ: {{inserted}} नए, {{updated}} अपडेटेड, {{skipped}} अपरिवर्तित",
"Hardcover notes sync failed: {{error}}": "Hardcover नोट्स सिंक विफल: {{error}}",
"Reading progress synced to Hardcover": "पढ़ने की प्रगति Hardcover से सिंक हो गई",
"Hardcover progress sync failed: {{error}}": "Hardcover प्रगति सिंक विफल: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "मौजूदा स्रोत पहचानकर्ता रखें",
"Toggle Toolbar": "टूलबार टॉगल करें"
}
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,6 @@
"Auto Mode": "Mode Otomatis",
"Behavior": "Perilaku",
"Book": "Buku",
"Book Cover": "Sampul Buku",
"Bookmark": "Penanda",
"Cancel": "Batal",
"Chapter": "Bab",
@@ -46,7 +45,6 @@
"Horizontal Direction": "Arah Horizontal",
"Hyphenation": "Pemenggalan Kata",
"Import Books": "Impor Buku",
"Language:": "Bahasa:",
"Layout": "Tata Letak",
"Light Mode": "Mode Terang",
"Loading...": "Memuat...",
@@ -68,8 +66,8 @@
"Paging Animation": "Animasi Halaman",
"Paragraph": "Paragraf",
"Parallel Read": "Baca Paralel",
"Published:": "Diterbitkan:",
"Publisher:": "Penerbit:",
"Published": "Diterbitkan",
"Publisher": "Penerbit",
"Reading Progress Synced": "Progres membaca disinkronkan",
"Reload Page": "Muat Ulang Halaman",
"Reveal in File Explorer": "Tampilkan di File Explorer",
@@ -83,7 +81,6 @@
"Search...": "Cari...",
"Select Book": "Pilih Buku",
"Select Books": "Pilih buku",
"Select Multiple Books": "Pilih beberapa buku",
"Sepia": "Sepia",
"Serif Font": "Font Serif",
"Show Book Details": "Tampilkan Detail Buku",
@@ -94,23 +91,21 @@
"Slow": "Lambat",
"Solarized": "Solarized",
"Speak": "Bicara",
"Subjects:": "Subjek:",
"Subjects": "Subjek",
"System Fonts": "Font Sistem",
"TTS not supported in this device": "TTS tidak didukung di perangkat ini",
"Theme Color": "Warna Tema",
"Theme Mode": "Mode Tema",
"Translate": "Terjemahkan",
"Translated Text": "Teks Terjemahan",
"Unknown": "Tidak Diketahui",
"Untitled": "Tanpa Judul",
"Updated:": "Diperbarui:",
"Updated": "Diperbarui",
"Version {{version}}": "Versi {{version}}",
"Vertical Direction": "Arah Vertikal",
"Welcome to your library. You can import your books here and read them anytime.": "Selamat datang di perpustakaan Anda. Anda dapat mengimpor buku-buku Anda di sini dan membacanya kapan saja.",
"Wikipedia": "Wikipedia",
"Writing Mode": "Mode Menulis",
"Your Library": "Perpustakaan Anda",
"TTS not supported for PDF": "TTS tidak didukung untuk PDF",
"Override Book Font": "Ganti Font Buku",
"Apply to All Books": "Terapkan ke semua buku",
"Apply to This Book": "Terapkan ke buku ini",
@@ -120,6 +115,7 @@
"Book Details": "Detail Buku",
"From Local File": "Dari file lokal",
"TOC": "Daftar Isi",
"Table of Contents": "Daftar Isi",
"Book uploaded: {{title}}": "Buku diunggah: {{title}}",
"Failed to upload book: {{title}}": "Gagal mengunggah buku: {{title}}",
"Book downloaded: {{title}}": "Buku diunduh: {{title}}",
@@ -176,9 +172,6 @@
"Token": "Token",
"Your OTP token": "Token OTP Anda",
"Verify token": "Verifikasi token",
"Sign in with Google": "Masuk dengan Google",
"Sign in with Apple": "Masuk dengan Apple",
"Sign in with GitHub": "Masuk dengan GitHub",
"Account": "Akun",
"Failed to delete user. Please try again later.": "Gagal menghapus pengguna. Silakan coba lagi nanti.",
"Community Support": "Dukungan Komunitas",
@@ -191,12 +184,11 @@
"RTL Direction": "Arah RTL",
"Maximum Column Height": "Tinggi Kolom Maksimum",
"Maximum Column Width": "Lebar Kolom Maksimum",
"Continuous Scroll": "Gulir Terus",
"Fullscreen": "Layar Penuh",
"No supported files found. Supported formats: {{formats}}": "Tidak ada file yang didukung ditemukan. Format yang didukung: {{formats}}",
"Drop to Import Books": "Jatuhkan untuk Mengimpor Buku",
"Custom": "Kustom",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Seluruh dunia adalah panggung,\nDan semua pria dan wanita hanyalah pemain;\nMereka memiliki keluar dan masuk mereka,\nDan seorang pria dalam hidupnya memainkan banyak peran,\nTindakannya ada tujuh zaman.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Seluruh dunia adalah panggung,\nDan semua pria dan wanita hanyalah pemain;\nMereka memiliki keluar dan masuk mereka,\nDan seorang pria dalam hidupnya memainkan banyak peran,\nTindakannya ada tujuh zaman.\n\n— William Shakespeare",
"Custom Theme": "Tema Kustom",
"Theme Name": "Nama Tema",
"Text Color": "Warna Teks",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "Impor Otomatis saat File Dibuka",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "Tidak ada bab yang terdeteksi.",
"Failed to parse the EPUB file.": "Gagal mengurai file EPUB.",
"This book format is not supported.": "Format buku ini tidak didukung.",
"No chapters detected": "Tidak ada bab yang terdeteksi",
"Failed to parse the EPUB file": "Gagal mengurai file EPUB",
"This book format is not supported": "Format buku ini tidak didukung",
"Unable to fetch the translation. Please log in first and try again.": "Tidak dapat mengambil terjemahan. Silakan masuk terlebih dahulu dan coba lagi.",
"Group": "Grup",
"Always on Top": "Selalu di Atas",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "Mengunduh {{downloaded}} dari {{contentLength}}",
"Download finished": "Unduhan selesai",
"DOWNLOAD & INSTALL": "UNDUH & INSTAL",
"Changelog:": "Catatan Perubahan:",
"Changelog": "Catatan Perubahan",
"Software Update": "Pembaruan Perangkat Lunak",
"Title": "Judul",
"Date Read": "Tanggal Dibaca",
@@ -253,18 +245,15 @@
"Ascending": "Naik",
"Descending": "Turun",
"Sort by...": "Urutkan berdasarkan...",
"Added:": "Ditambahkan:",
"Format:": "Format:",
"Added": "Ditambahkan",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "Deskripsi:",
"Description": "Deskripsi",
"No description available": "Tidak ada deskripsi yang tersedia",
"List": "Daftar",
"Grid": "Jala",
"(from 'As You Like It', Act II)": "(dari 'Seperti yang Anda Inginkan', Bab II)",
"Link Color": "Warna Tautan",
"Volume Keys for Page Flip": "Volume Keys untuk Pembalikan Halaman",
"Clicks for Page Flip": "Klik untuk Pembalikan Halaman",
"Swap Clicks Area": "Area Klik Tukar",
"Screen": "Screen",
"Orientation": "Orientasi",
"Portrait": "Potret",
@@ -273,7 +262,7 @@
"Checking for updates...": "Memeriksa pembaruan...",
"Error checking for updates": "Kesalahan saat memeriksa pembaruan",
"Details": "Detail",
"File Size:": "Ukuran File:",
"File Size": "Ukuran File",
"Auto Detect": "Deteksi Otomatis",
"Next Section": "Bagian Selanjutnya",
"Previous Section": "Bagian Sebelumnya",
@@ -299,7 +288,6 @@
"Disable Translation": "Nonaktifkan Terjemahan",
"Scroll": "Scroll",
"Overlap Pixels": "Overlap Piksel",
"Click": "Klik",
"System Language": "Bahasa Sistem",
"Security": "Keamanan",
"Allow JavaScript": "Izinkan JavaScript",
@@ -312,7 +300,6 @@
"Synced at {{time}}": "Disinkronkan pada {{time}}",
"Never synced": "Belum pernah disinkronkan",
"Show Remaining Time": "Perlihatkan Waktu Tersisa",
"Show Page Number": "Perlihatkan Nomor Halaman",
"{{time}} min left in chapter": "{{time}} menit tersisa di bab",
"Override Book Color": "Ubah Warna Buku",
"Login Required": "Perlu masuk",
@@ -334,7 +321,6 @@
"Left Margin (px)": "Margin Kiri (px)",
"Column Gap (%)": "Jarak Antar Kolom (%)",
"Always Show Status Bar": "Selalu Tampilkan Bilah Status",
"Translation Not Available": "Terjemahan Tidak Tersedia",
"Custom Content CSS": "CSS konten",
"Enter CSS for book content styling...": "Masukkan CSS untuk gaya konten buku...",
"Custom Reader UI CSS": "CSS antarmuka",
@@ -344,10 +330,10 @@
"Fit": "Pas",
"Reset {{settings}}": "Atur Ulang {{settings}}",
"Reset Settings": "Atur Ulang Pengaturan",
"{{count}} pages left in chapter_other": "{{count}} halaman tersisa di bab ini",
"{{count}} pages left in chapter_other": "<0>{{count}}</0><1> halaman tersisa di bab ini</1>",
"Show Remaining Pages": "Tampilkan halaman tersisa",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Kelola Langganan",
"Coming Soon": "Segera Hadir",
@@ -355,7 +341,6 @@
"Upgrade to Plus or Pro": "Tingkatkan ke Plus atau Pro",
"Current Plan": "Paket Saat Ini",
"Plan Limits": "Batas Paket",
"Failed to manage subscription. Please try again later.": "Gagal mengelola langganan. Silakan coba lagi nanti.",
"Processing your payment...": "Memproses pembayaran Anda...",
"Please wait while we confirm your subscription.": "Mohon tunggu saat kami mengonfirmasi langganan Anda.",
"Payment Processing": "Memproses Pembayaran",
@@ -368,7 +353,6 @@
"Email:": "Email:",
"Plan:": "Paket:",
"Amount:": "Jumlah:",
"Subscription ID:": "ID Langganan:",
"Go to Library": "Pergi ke Perpustakaan",
"Need help? Contact our support team at support@readest.com": "Perlu bantuan? Hubungi tim dukungan kami di support@readest.com",
"Free Plan": "Paket Gratis",
@@ -380,7 +364,7 @@
"More AI Translations": "Lebih Banyak Terjemahan AI",
"Complete Your Subscription": "Selesaikan Langganan Anda",
"{{percentage}}% of Cloud Sync Space Used.": "{{percentage}}% ruang sinkronisasi cloud terpakai",
"Cloud Sync Storage": "Ruang cloud",
"Cloud Sync Storage": "Penyimpanan Sinkronisasi Cloud",
"Disable": "Nonaktifkan",
"Enable": "Aktifkan",
"Upgrade to Readest Premium": "Tingkatkan ke Readest Premium",
@@ -397,7 +381,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "Dengarkan sebanyak yang Anda mau tanpa batas.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Dapatkan lebih banyak kuota dan fitur terjemahan lanjutan.",
"DeepL Pro Access": "Akses DeepL Pro",
"2 GB Cloud Sync Storage": "Penyimpanan Sinkronisasi Cloud 2 GB",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Nikmati dukungan prioritas kapan saja.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Kuota harian habis. Tingkatkan paket Anda untuk lanjut.",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Terjemahkan teks apa pun secara instan dengan kekuatan Google, Azure, atau DeepL—pahami konten dalam bahasa apa pun.",
@@ -408,10 +391,784 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Manfaatkan alat AI canggih untuk membaca cerdas, terjemahan, dan penemuan konten.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Terjemahkan hingga 100.000 karakter harian dengan mesin terjemahan paling akurat.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Terjemahkan hingga 500.000 karakter harian dengan mesin terjemahan paling akurat.",
"10 GB Cloud Sync Storage": "Penyimpanan Cloud Sync 10 GB",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "Simpan dan akses koleksi bacaan lengkap dengan aman menggunakan penyimpanan cloud 2 GB.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "Simpan dan akses koleksi bacaan lengkap dengan aman menggunakan penyimpanan cloud 10 GB.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Simpan dan akses koleksi bacaan lengkap dengan aman menggunakan penyimpanan cloud 5 GB.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Simpan dan akses koleksi bacaan lengkap dengan aman menggunakan penyimpanan cloud 20 GB.",
"Deleted cloud backup of the book: {{title}}": "Cadangan cloud buku dihapus: {{title}}",
"Failed to delete cloud backup of the book": "Cadangan cloud buku gagal dihapus",
"Are you sure to delete the cloud backup of the selected book?": "Apakah Anda yakin ingin menghapus cadangan cloud dari buku yang dipilih?"
"Are you sure to delete the cloud backup of the selected book?": "Apakah Anda yakin ingin menghapus cadangan cloud dari buku yang dipilih?",
"What's New in Readest": "Yang Baru di Readest",
"Enter book title": "Masukkan judul buku",
"Subtitle": "Subjudul",
"Enter book subtitle": "Masukkan subjudul buku",
"Enter author name": "Masukkan nama penulis",
"Series": "Seri",
"Enter series name": "Masukkan nama seri",
"Series Index": "Nomor seri",
"Enter series index": "Masukkan nomor seri",
"Total in Series": "Total dalam seri",
"Enter total books in series": "Masukkan total buku dalam seri",
"Enter publisher": "Masukkan penerbit",
"Publication Date": "Tanggal terbit",
"Identifier": "Pengidentifikasi",
"Enter book description": "Masukkan deskripsi buku",
"Change cover image": "Ubah gambar sampul",
"Replace": "Ganti",
"Unlock cover": "Buka kunci sampul",
"Lock cover": "Kunci sampul",
"Auto-Retrieve Metadata": "Ambil metadata otomatis",
"Auto-Retrieve": "Ambil otomatis",
"Unlock all fields": "Buka kunci semua field",
"Unlock All": "Buka semua",
"Lock all fields": "Kunci semua field",
"Lock All": "Kunci semua",
"Reset": "Reset",
"Edit Metadata": "Edit metadata",
"Locked": "Terkunci",
"Select Metadata Source": "Pilih sumber metadata",
"Keep manual input": "Pertahankan input manual",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Fiksi, Sains, Sejarah",
"Open Book in New Window": "Buka Buku di Jendela Baru",
"Voices for {{lang}}": "Suara untuk {{lang}}",
"Yandex Translate": "Yandex Translate",
"YYYY or YYYY-MM-DD": "YYYY atau YYYY-MM-DD",
"Restore Purchase": "Pulihkan Pembelian",
"No purchases found to restore.": "Tidak ada pembelian yang ditemukan untuk dipulihkan.",
"Failed to restore purchases.": "Gagal memulihkan pembelian.",
"Failed to manage subscription.": "Gagal mengelola langganan.",
"Failed to load subscription plans.": "Gagal memuat rencana langganan.",
"year": "tahun",
"Failed to create checkout session": "Gagal membuat sesi checkout",
"Storage": "Penyimpanan",
"Terms of Service": "Ketentuan Layanan",
"Privacy Policy": "Kebijakan Privasi",
"Disable Double Click": "Nonaktifkan Klik Ganda",
"TTS not supported for this document": "TTS tidak didukung untuk dokumen ini",
"Reset Password": "Reset Kata Sandi",
"Show Reading Progress": "Perlihatkan Progres Membaca",
"Reading Progress Style": "Gaya Progres Membaca",
"Page Number": "Nomor Halaman",
"Percentage": "Persentase",
"Deleted local copy of the book: {{title}}": "Salinan lokal buku dihapus: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Gagal menghapus cadangan cloud buku: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Gagal menghapus salinan lokal buku: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Apakah Anda yakin ingin menghapus salinan lokal buku yang dipilih?",
"Remove from Cloud & Device": "Hapus dari Cloud & Perangkat",
"Remove from Cloud Only": "Hapus dari Cloud Saja",
"Remove from Device Only": "Hapus dari Perangkat Saja",
"Disconnected": "Terputus",
"KOReader Sync Settings": "Pengaturan Sinkronisasi KOReader",
"Sync Strategy": "Strategi Sinkronisasi",
"Ask on conflict": "Tanya saat terjadi konflik",
"Always use latest": "Selalu gunakan yang terbaru",
"Send changes only": "Kirim perubahan saja",
"Receive changes only": "Terima perubahan saja",
"Checksum Method": "Metode Checksum",
"File Content (recommended)": "Konten File (disarankan)",
"File Name": "Nama File",
"Device Name": "Nama Perangkat",
"Connect to your KOReader Sync server.": "Hubungkan ke server Sinkronisasi KOReader Anda.",
"Server URL": "URL Server",
"Username": "Nama Pengguna",
"Your Username": "Nama Pengguna Anda",
"Password": "Kata Sandi",
"Connect": "Hubungkan",
"KOReader Sync": "Sinkronisasi KOReader",
"Sync Conflict": "Konflik Sinkronisasi",
"Sync reading progress from \"{{deviceName}}\"?": "Sinkronkan progres membaca dari \"{{deviceName}}\"?",
"another device": "perangkat lain",
"Local Progress": "Progres Lokal",
"Remote Progress": "Progres Jarak Jauh",
"Page {{page}} of {{total}} ({{percentage}}%)": "Halaman {{page}} dari {{total}} ({{percentage}}%)",
"Current position": "Posisi Saat Ini",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Sekitar halaman {{page}} dari {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Sekitar {{percentage}}%",
"Failed to connect": "Gagal terhubung",
"Sync Server Connected": "Server sinkronisasi terhubung",
"Sync as {{userDisplayName}}": "Sinkronkan sebagai {{userDisplayName}}",
"Custom Fonts": "Font Kustom",
"Cancel Delete": "Batal Hapus",
"Import Font": "Impor Font",
"Delete Font": "Hapus Font",
"Tips": "Tips",
"Custom fonts can be selected from the Font Face menu": "Font kustom dapat dipilih dari menu Font Face",
"Manage Custom Fonts": "Kelola Font Kustom",
"Select Files": "Pilih File",
"Select Image": "Pilih Gambar",
"Select Video": "Pilih Video",
"Select Audio": "Pilih Audio",
"Select Fonts": "Pilih Font",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Format font yang didukung: .ttf, .otf, .woff, .woff2",
"Push Progress": "Dorong Progres",
"Pull Progress": "Tarik Progres",
"Previous Paragraph": "Paragraf Sebelumnya",
"Previous Sentence": "Kalimat Sebelumnya",
"Pause": "Jeda",
"Play": "Putar",
"Next Sentence": "Kalimat Berikutnya",
"Next Paragraph": "Paragraf Berikutnya",
"Separate Cover Page": "Halaman Sampul Terpisah",
"Resize Notebook": "Ubah Ukuran Buku Catatan",
"Resize Sidebar": "Ubah Ukuran Bilah Samping",
"Get Help from the Readest Community": "Dapatkan Bantuan dari Komunitas Readest",
"Remove cover image": "Hapus gambar sampul",
"Bookshelf": "Rak Buku",
"View Menu": "Lihat Menu",
"Settings Menu": "Menu Pengaturan",
"View account details and quota": "Lihat detail akun dan kuota",
"Library Header": "Header Perpustakaan",
"Book Content": "Isi Buku",
"Footer Bar": "Bilah Footer",
"Header Bar": "Bilah Header",
"View Options": "Opsi Tampilan",
"Book Menu": "Menu Buku",
"Search Options": "Opsi Pencarian",
"Close": "Tutup",
"Delete Book Options": "Opsi Hapus Buku",
"ON": "AKTIF",
"OFF": "TIDAK AKTIF",
"Reading Progress": "Progres Membaca",
"Page Margin": "Margin Halaman",
"Remove Bookmark": "Hapus Penanda",
"Add Bookmark": "Tambahkan Penanda",
"Books Content": "Isi Buku",
"Jump to Location": "Lompat ke Lokasi",
"Unpin Notebook": "Batal Pin Notebook",
"Pin Notebook": "Pin Notebook",
"Hide Search Bar": "Sembunyikan Bilah Pencarian",
"Show Search Bar": "Tampilkan Bilah Pencarian",
"On {{current}} of {{total}} page": "Pada {{current}} dari {{total}} halaman",
"Section Title": "Judul Bagian",
"Decrease": "Kecilkan",
"Increase": "Besarakan",
"Settings Panels": "Panel Pengaturan",
"Settings": "Pengaturan",
"Unpin Sidebar": "Batal Pin Bilah Samping",
"Pin Sidebar": "Pin Bilah Samping",
"Toggle Sidebar": "Toggel Bilah Samping",
"Toggle Translation": "Toggel Terjemahan",
"Translation Disabled": "Terjemahan Dinonaktifkan",
"Minimize": "Minimalkan",
"Maximize or Restore": "Maksimalkan atau Pulihkan",
"Exit Parallel Read": "Keluar dari Baca Paralel",
"Enter Parallel Read": "Masuk ke Baca Paralel",
"Zoom Level": "Level Zoom",
"Zoom Out": "Perbesar Zoom",
"Reset Zoom": "Reset Zoom",
"Zoom In": "Perkecil Zoom",
"Zoom Mode": "Mode Zoom",
"Single Page": "Halaman Tunggal",
"Auto Spread": "Penyebaran Otomatis",
"Fit Page": "Sesuaikan Halaman",
"Fit Width": "Sesuaikan Lebar",
"Failed to select directory": "Gagal memilih direktori",
"The new data directory must be different from the current one.": "Direktori data baru harus berbeda dari yang saat ini.",
"Migration failed: {{error}}": "Migrasi gagal: {{error}}",
"Change Data Location": "Ubah Lokasi Data",
"Current Data Location": "Lokasi Data Saat Ini",
"Total size: {{size}}": "Ukuran total: {{size}}",
"Calculating file info...": "Menghitung informasi file...",
"New Data Location": "Lokasi Data Baru",
"Choose Different Folder": "Pilih Folder Berbeda",
"Choose New Folder": "Pilih Folder Baru",
"Migrating data...": "Migrasi data...",
"Copying: {{file}}": "Menyalin: {{file}}",
"{{current}} of {{total}} files": "{{current}} dari {{total}} file",
"Migration completed successfully!": "Migrasi selesai dengan sukses!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Data Anda telah dipindahkan ke lokasi baru. Silakan restart aplikasi untuk menyelesaikan proses.",
"Migration failed": "Migrasi gagal",
"Important Notice": "Pemberitahuan Penting",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Ini akan memindahkan semua data aplikasi Anda ke lokasi baru. Pastikan tujuan memiliki cukup ruang kosong.",
"Restart App": "Restart Aplikasi",
"Start Migration": "Mulai Migrasi",
"Advanced Settings": "Pengaturan Lanjutan",
"File count: {{size}}": "Jumlah file: {{size}}",
"Background Read Aloud": "Bacakan Latar Belakang",
"Ready to read aloud": "Siap untuk dibacakan",
"Read Aloud": "Bacakan",
"Screen Brightness": "Kecerahan Layar",
"Background Image": "Gambar Latar Belakang",
"Import Image": "Impor Gambar",
"Opacity": "Keburaman",
"Size": "Ukuran",
"Cover": "Sampul",
"Contain": "Mengandung",
"{{number}} pages left in chapter": "<0>{{number}}</0><1> halaman tersisa di bab</1>",
"Device": "Perangkat",
"E-Ink Mode": "Mode E-Ink",
"Highlight Colors": "Warna Sorotan",
"Pagination": "Paginasi",
"Disable Double Tap": "Nonaktifkan Ketuk Ganda",
"Tap to Paginate": "Ketuk untuk Paginasi",
"Click to Paginate": "Klik untuk Paginasi",
"Tap Both Sides": "Ketuk Kedua Sisi",
"Click Both Sides": "Klik Kedua Sisi",
"Swap Tap Sides": "Tukar Sisi Ketuk",
"Swap Click Sides": "Tukar Sisi Klik",
"Source and Translated": "Sumber dan Terjemahan",
"Translated Only": "Hanya Terjemahan",
"Source Only": "Hanya Sumber",
"TTS Text": "Teks TTS",
"The book file is corrupted": "File buku rusak",
"The book file is empty": "File buku kosong",
"Failed to open the book file": "Gagal membuka file buku",
"On-Demand Purchase": "Pembelian Sesuai Permintaan",
"Full Customization": "Kustomisasi Penuh",
"Lifetime Plan": "Rencana Seumur Hidup",
"One-Time Payment": "Pembayaran Sekali",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Lakukan pembayaran sekali untuk menikmati akses seumur hidup ke fitur tertentu di semua perangkat. Beli fitur atau layanan tertentu hanya saat Anda membutuhkannya.",
"Expand Cloud Sync Storage": "Perluas Penyimpanan Sinkronisasi Cloud",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Perluas penyimpanan cloud Anda selamanya dengan pembelian sekali. Setiap pembelian tambahan menambah lebih banyak ruang.",
"Unlock All Customization Options": "Buka Semua Opsi Kustomisasi",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Buka tema tambahan, font, opsi tata letak, dan baca nyaring, penerjemah, layanan penyimpanan cloud.",
"Purchase Successful!": "Pembelian Berhasil!",
"lifetime": "seumur hidup",
"Thank you for your purchase! Your payment has been processed successfully.": "Terima kasih atas pembelian Anda! Pembayaran Anda telah berhasil diproses.",
"Order ID:": "ID Pesanan:",
"TTS Highlighting": "TTS Menyorot",
"Style": "Gaya",
"Underline": "Garisan Bawah",
"Strikethrough": "Garis Tengah",
"Squiggly": "Bergelombang",
"Outline": "Garis Besar",
"Save Current Color": "Simpan Warna Saat Ini",
"Quick Colors": "Warna Cepat",
"Highlighter": "Penyorot",
"Save Book Cover": "Simpan Sampul Buku",
"Auto-save last book cover": "Simpan otomatis sampul buku terakhir",
"Back": "Kembali",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Email konfirmasi telah dikirim! Silakan periksa alamat email lama dan baru Anda untuk mengonfirmasi perubahan.",
"Failed to update email": "Gagal memperbarui email",
"New Email": "Email baru",
"Your new email": "Email baru Anda",
"Updating email ...": "Memperbarui email ...",
"Update email": "Perbarui email",
"Current email": "Email saat ini",
"Update Email": "Perbarui email",
"All": "Semua",
"Unable to open book": "Tidak dapat membuka buku",
"Punctuation": "Tanda Baca",
"Replace Quotation Marks": "Ganti Tanda Kutip",
"Enabled only in vertical layout.": "Hanya diaktifkan dalam tata letak vertikal.",
"No Conversion": "Tanpa konversi",
"Simplified to Traditional": "Sederhana → Tradisional",
"Traditional to Simplified": "Tradisional → Sederhana",
"Simplified to Traditional (Taiwan)": "Sederhana → Tradisional (Taiwan)",
"Simplified to Traditional (Hong Kong)": "Sederhana → Tradisional (Hong Kong)",
"Simplified to Traditional (Taiwan), with phrases": "Sederhana → Tradisional (Taiwan • frasa)",
"Traditional (Taiwan) to Simplified": "Tradisional (Taiwan) → Sederhana",
"Traditional (Hong Kong) to Simplified": "Tradisional (Hong Kong) → Sederhana",
"Traditional (Taiwan) to Simplified, with phrases": "Tradisional (Taiwan • frasa) → Sederhana",
"Convert Simplified and Traditional Chinese": "Konversi Tionghoa Sederhana/Tradisional",
"Convert Mode": "Mode Konversi",
"Failed to auto-save book cover for lock screen: {{error}}": "Gagal menyimpan otomatis sampul buku untuk layar kunci: {{error}}",
"Download from Cloud": "Unduh dari Cloud",
"Upload to Cloud": "Unggah ke Cloud",
"Clear Custom Fonts": "Bersihkan Font Kustom",
"Columns": "Kolom",
"OPDS Catalogs": "Katalog OPDS",
"Adding LAN addresses is not supported in the web app version.": "Menambahkan alamat LAN tidak didukung di versi web.",
"Invalid OPDS catalog. Please check the URL.": "Katalog OPDS tidak valid. Silakan periksa URL-nya.",
"Browse and download books from online catalogs": "Jelajahi dan unduh buku dari katalog online",
"My Catalogs": "Katalog Saya",
"Add Catalog": "Tambah Katalog",
"No catalogs yet": "Belum ada katalog",
"Add your first OPDS catalog to start browsing books": "Tambahkan katalog OPDS pertama Anda untuk mulai menjelajahi buku",
"Add Your First Catalog": "Tambah Katalog Pertama Anda",
"Browse": "Jelajahi",
"Popular Catalogs": "Katalog Populer",
"Add": "Tambah",
"Add OPDS Catalog": "Tambah Katalog OPDS",
"Catalog Name": "Nama Katalog",
"My Calibre Library": "Perpustakaan Calibre Saya",
"OPDS URL": "URL OPDS",
"Username (optional)": "Username (opsional)",
"Password (optional)": "Password (opsional)",
"Description (optional)": "Deskripsi (opsional)",
"A brief description of this catalog": "Deskripsi singkat untuk katalog ini",
"Validating...": "Memvalidasi...",
"View All": "Lihat Semua",
"Forward": "Maju",
"Home": "Beranda",
"{{count}} items_other": "{{count}} item",
"Download completed": "Unduhan selesai",
"Download failed": "Unduhan gagal",
"Open Access": "Akses Terbuka",
"Borrow": "Pinjam",
"Buy": "Beli",
"Subscribe": "Berlangganan",
"Sample": "Contoh",
"Download": "Unduh",
"Open & Read": "Buka & Baca",
"Tags": "Tag",
"Tag": "Tag",
"First": "Pertama",
"Previous": "Sebelumnya",
"Next": "Berikutnya",
"Last": "Terakhir",
"Cannot Load Page": "Tidak dapat memuat halaman",
"An error occurred": "Terjadi kesalahan",
"Online Library": "Perpustakaan Online",
"URL must start with http:// or https://": "URL harus diawali dengan http:// atau https://",
"Title, Author, Tag, etc...": "Judul, Penulis, Tag, dll...",
"Query": "Kueri",
"Subject": "Subjek",
"Enter {{terms}}": "Masukkan {{terms}}",
"No search results found": "Tidak ada hasil pencarian ditemukan",
"Failed to load OPDS feed: {{status}} {{statusText}}": "Gagal memuat feed OPDS: {{status}} {{statusText}}",
"Search in {{title}}": "Cari di {{title}}",
"Manage Storage": "Kelola Penyimpanan",
"Failed to load files": "Gagal memuat file",
"Deleted {{count}} file(s)_other": "{{count}} file dihapus",
"Failed to delete {{count}} file(s)_other": "Gagal menghapus {{count}} file",
"Failed to delete files": "Gagal menghapus file",
"Total Files": "Total File",
"Total Size": "Total Ukuran",
"Quota": "Kuota",
"Used": "Digunakan",
"Files": "File",
"Search files...": "Cari file...",
"Newest First": "Terbaru",
"Oldest First": "Terlama",
"Largest First": "Terbesar",
"Smallest First": "Terkecil",
"Name A-Z": "Nama A-Z",
"Name Z-A": "Nama Z-A",
"{{count}} selected_other": "{{count}} dipilih",
"Delete Selected": "Hapus yang Dipilih",
"Created": "Dibuat",
"No files found": "Tidak ada file ditemukan",
"No files uploaded yet": "Belum ada file diunggah",
"files": "file",
"Page {{current}} of {{total}}": "Halaman {{current}} dari {{total}}",
"Are you sure to delete {{count}} selected file(s)?_other": "Yakin ingin menghapus {{count}} file yang dipilih?",
"Cloud Storage Usage": "Penggunaan Penyimpanan Cloud",
"Rename Group": "Ganti Nama Grup",
"From Directory": "Dari Direktori",
"Successfully imported {{count}} book(s)_other": "Berhasil mengimpor {{count}} buku",
"Count": "Jumlah",
"Start Page": "Halaman Awal",
"Search in OPDS Catalog...": "Cari di Katalog OPDS...",
"Please log in to use advanced TTS features": "Silakan masuk untuk menggunakan fitur TTS lanjutan",
"Word limit of 30 words exceeded.": "Batas 30 kata telah terlampaui.",
"Proofread": "Koreksi",
"Current selection": "Pilihan saat ini",
"All occurrences in this book": "Semua kemunculan di buku ini",
"All occurrences in your library": "Semua kemunculan di perpustakaan Anda",
"Selected text:": "Teks terpilih:",
"Replace with:": "Ganti dengan:",
"Enter text...": "Masukkan teks…",
"Case sensitive:": "Peka huruf besar dan kecil:",
"Scope:": "Cakupan:",
"Selection": "Pilihan",
"Library": "Perpustakaan",
"Yes": "Ya",
"No": "Tidak",
"Proofread Replacement Rules": "Aturan penggantian koreksi",
"Selected Text Rules": "Aturan teks terpilih",
"No selected text replacement rules": "Tidak ada aturan penggantian untuk teks terpilih",
"Book Specific Rules": "Aturan khusus buku",
"No book-level replacement rules": "Tidak ada aturan penggantian tingkat buku",
"Disable Quick Action": "Nonaktifkan Aksi Cepat",
"Enable Quick Action on Selection": "Aktifkan Aksi Cepat saat memilih",
"None": "Tidak ada",
"Annotation Tools": "Alat Anotasi",
"Enable Quick Actions": "Aktifkan Aksi Cepat",
"Quick Action": "Aksi Cepat",
"Copy to Notebook": "Salin ke Buku Catatan",
"Copy text after selection": "Salin teks setelah pemilihan",
"Highlight text after selection": "Sorot teks setelah pemilihan",
"Annotate text after selection": "Anotasi teks setelah pemilihan",
"Search text after selection": "Cari teks setelah pemilihan",
"Look up text in dictionary after selection": "Cari teks di kamus setelah pemilihan",
"Look up text in Wikipedia after selection": "Cari teks di Wikipedia setelah pemilihan",
"Translate text after selection": "Terjemahkan teks setelah pemilihan",
"Read text aloud after selection": "Bacakan teks setelah pemilihan",
"Proofread text after selection": "Periksa teks setelah pemilihan",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} aktif, {{pendingCount}} menunggu",
"{{failedCount}} failed": "{{failedCount}} gagal",
"Waiting...": "Menunggu...",
"Failed": "Gagal",
"Completed": "Selesai",
"Cancelled": "Dibatalkan",
"Retry": "Coba lagi",
"Active": "Aktif",
"Transfer Queue": "Antrian Transfer",
"Upload All": "Unggah Semua",
"Download All": "Unduh Semua",
"Resume Transfers": "Lanjutkan Transfer",
"Pause Transfers": "Jeda Transfer",
"Pending": "Menunggu",
"No transfers": "Tidak ada transfer",
"Retry All": "Coba Semua Lagi",
"Clear Completed": "Hapus Selesai",
"Clear Failed": "Hapus Gagal",
"Upload queued: {{title}}": "Unggahan dalam antrian: {{title}}",
"Download queued: {{title}}": "Unduhan dalam antrian: {{title}}",
"Book not found in library": "Buku tidak ditemukan di perpustakaan",
"Unknown error": "Kesalahan tidak diketahui",
"Please log in to continue": "Silakan masuk untuk melanjutkan",
"Cloud File Transfers": "Transfer File Cloud",
"Show Search Results": "Tampilkan hasil pencarian",
"Search results for '{{term}}'": "Hasil untuk '{{term}}'",
"Close Search": "Tutup pencarian",
"Previous Result": "Hasil sebelumnya",
"Next Result": "Hasil berikutnya",
"Bookmarks": "Penanda",
"Annotations": "Anotasi",
"Show Results": "Tampilkan Hasil",
"Clear search": "Hapus pencarian",
"Clear search history": "Hapus riwayat pencarian",
"Tap to Toggle Footer": "Ketuk untuk beralih footer",
"Show Current Time": "Tampilkan Waktu Sekarang",
"Use 24 Hour Clock": "Gunakan Format 24 Jam",
"Show Current Battery Status": "Tampilkan Status Baterai Saat Ini",
"Exported successfully": "Berhasil diekspor",
"Book exported successfully.": "Buku berhasil diekspor.",
"Failed to export the book.": "Gagal mengekspor buku.",
"Export Book": "Ekspor Buku",
"Whole word:": "Kata utuh:",
"Error": "Kesalahan",
"Unable to load the article. Try searching directly on {{link}}.": "Tidak dapat memuat artikel. Coba cari langsung di {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Tidak dapat memuat kata. Coba cari langsung di {{link}}.",
"Date Published": "Tanggal terbit",
"Only for TTS:": "Hanya untuk TTS:",
"Uploaded": "Diunggah",
"Downloaded": "Diunduh",
"Deleted": "Dihapus",
"Note:": "Catatan:",
"Time:": "Waktu:",
"Format Options": "Opsi Format",
"Export Date": "Tanggal Ekspor",
"Chapter Titles": "Judul Bab",
"Chapter Separator": "Pemisah Bab",
"Highlights": "Sorotan",
"Note Date": "Tanggal Catatan",
"Advanced": "Lanjutan",
"Hide": "Sembunyikan",
"Show": "Tampilkan",
"Use Custom Template": "Gunakan Template Kustom",
"Export Template": "Template Ekspor",
"Template Syntax:": "Sintaks Template:",
"Insert value": "Masukkan nilai",
"Format date (locale)": "Format tanggal (lokal)",
"Format date (custom)": "Format tanggal (kustom)",
"Conditional": "Kondisional",
"Loop": "Loop",
"Available Variables:": "Variabel yang Tersedia:",
"Book title": "Judul buku",
"Book author": "Penulis buku",
"Export date": "Tanggal ekspor",
"Array of chapters": "Daftar bab",
"Chapter title": "Judul bab",
"Array of annotations": "Daftar anotasi",
"Highlighted text": "Teks yang disorot",
"Annotation note": "Catatan anotasi",
"Date Format Tokens:": "Token Format Tanggal:",
"Year (4 digits)": "Tahun (4 digit)",
"Month (01-12)": "Bulan (01-12)",
"Day (01-31)": "Hari (01-31)",
"Hour (00-23)": "Jam (00-23)",
"Minute (00-59)": "Menit (00-59)",
"Second (00-59)": "Detik (00-59)",
"Show Source": "Tampilkan Sumber",
"No content to preview": "Tidak ada konten untuk dipratinjau",
"Export": "Ekspor",
"Set Timeout": "Atur batas waktu",
"Select Voice": "Pilih suara",
"Toggle Sticky Bottom TTS Bar": "Alihkan bilah TTS tetap",
"Display what I'm reading on Discord": "Tampilkan buku yang sedang dibaca di Discord",
"Show on Discord": "Tampilkan di Discord",
"Instant {{action}}": "{{action}} Instan",
"Instant {{action}} Disabled": "{{action}} Instan Dinonaktifkan",
"Annotation": "Anotasi",
"Reset Template": "Atur Ulang Template",
"Annotation style": "Gaya anotasi",
"Annotation color": "Warna anotasi",
"Annotation time": "Waktu anotasi",
"AI": "AI",
"Are you sure you want to re-index this book?": "Apakah Anda yakin ingin mengindeks ulang buku ini?",
"Enable AI in Settings": "Aktifkan AI di Pengaturan",
"Index This Book": "Indeks Buku Ini",
"Enable AI search and chat for this book": "Aktifkan pencarian AI dan obrolan untuk buku ini",
"Start Indexing": "Mulai Mengindeks",
"Indexing book...": "Mengindeks buku...",
"Preparing...": "Mempersiapkan...",
"Delete this conversation?": "Hapus percakapan ini?",
"No conversations yet": "Belum ada percakapan",
"Start a new chat to ask questions about this book": "Mulai obrolan baru untuk mengajukan pertanyaan tentang buku ini",
"Rename": "Ubah nama",
"New Chat": "Obrolan Baru",
"Chat": "Obrolan",
"Please enter a model ID": "Silakan masukkan ID model",
"Model not available or invalid": "Model tidak tersedia atau tidak valid",
"Failed to validate model": "Gagal memvalidasi model",
"Couldn't connect to Ollama. Is it running?": "Tidak dapat terhubung ke Ollama. Apakah sedang berjalan?",
"Invalid API key or connection failed": "Kunci API tidak valid atau koneksi gagal",
"Connection failed": "Koneksi gagal",
"AI Assistant": "Asisten AI",
"Enable AI Assistant": "Aktifkan Asisten AI",
"Provider": "Penyedia",
"Ollama (Local)": "Ollama (Lokal)",
"AI Gateway (Cloud)": "Gateway AI (Cloud)",
"Ollama Configuration": "Konfigurasi Ollama",
"Refresh Models": "Segarkan Model",
"AI Model": "Model AI",
"No models detected": "Tidak ada model terdeteksi",
"AI Gateway Configuration": "Konfigurasi Gateway AI",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Pilih dari pilihan model AI berkualitas tinggi dan ekonomis. Anda juga dapat menggunakan model Anda sendiri dengan memilih \"Model Kustom\" di bawah.",
"API Key": "Kunci API",
"Get Key": "Dapatkan Kunci",
"Model": "Model",
"Custom Model...": "Model Kustom...",
"Custom Model ID": "ID Model Kustom",
"Validate": "Validasi",
"Model available": "Model tersedia",
"Connection": "Koneksi",
"Test Connection": "Uji Koneksi",
"Connected": "Terhubung",
"Custom Colors": "Warna Kustom",
"Color E-Ink Mode": "Mode E-Ink Berwarna",
"Reading Ruler": "Penggaris Membaca",
"Enable Reading Ruler": "Aktifkan Penggaris Membaca",
"Lines to Highlight": "Baris untuk Disorot",
"Ruler Color": "Warna Penggaris",
"Command Palette": "Palet Perintah",
"Search settings and actions...": "Cari pengaturan dan tindakan...",
"No results found for": "Tidak ada hasil ditemukan untuk",
"Type to search settings and actions": "Ketik untuk mencari pengaturan dan tindakan",
"Recent": "Terbaru",
"navigate": "navigasi",
"select": "pilih",
"close": "tutup",
"Search Settings": "Cari Pengaturan",
"Page Margins": "Margin Halaman",
"AI Provider": "Penyedia AI",
"Ollama URL": "URL Ollama",
"Ollama Model": "Model Ollama",
"AI Gateway Model": "Model AI Gateway",
"Actions": "Tindakan",
"Navigation": "Navigasi",
"Set status for {{count}} book(s)_other": "Atur status untuk {{count}} buku",
"Mark as Unread": "Tandai sebagai Belum Dibaca",
"Mark as Finished": "Tandai sebagai Selesai",
"Finished": "Selesai",
"Unread": "Belum Dibaca",
"Clear Status": "Hapus Status",
"Status": "Status",
"Loading": "Memuat...",
"Exit Paragraph Mode": "Keluar dari Mode Paragraf",
"Paragraph Mode": "Mode Paragraf",
"Embedding Model": "Model Penyematan",
"{{count}} book(s) synced_other": "{{count}} buku telah disinkronkan",
"Unable to start RSVP": "Tidak dapat memulai RSVP",
"RSVP not supported for PDF": "RSVP tidak didukung untuk PDF",
"Select Chapter": "Pilih Bab",
"Context": "Konteks",
"Ready": "Siap",
"Chapter Progress": "Kemajuan Bab",
"words": "kata",
"{{time}} left": "{{time}} tersisa",
"Reading progress": "Kemajuan membaca",
"Skip back 15 words": "Lompat mundur 15 kata",
"Back 15 words (Shift+Left)": "Mundur 15 kata (Shift+Kiri)",
"Pause (Space)": "Jeda (Spasi)",
"Play (Space)": "Putar (Spasi)",
"Skip forward 15 words": "Lompat maju 15 kata",
"Forward 15 words (Shift+Right)": "Maju 15 kata (Shift+Kanan)",
"Decrease speed": "Kurangi kecepatan",
"Slower (Left/Down)": "Lebih lambat (Kiri/Bawah)",
"Increase speed": "Tambah kecepatan",
"Faster (Right/Up)": "Lebih cepat (Kanan/Atas)",
"Start RSVP Reading": "Mulai Membaca RSVP",
"Choose where to start reading": "Pilih tempat untuk mulai membaca",
"From Chapter Start": "Dari Awal Bab",
"Start reading from the beginning of the chapter": "Mulai membaca dari awal bab",
"Resume": "Lanjutkan",
"Continue from where you left off": "Lanjutkan dari tempat Anda berhenti",
"From Current Page": "Dari Halaman Saat Ini",
"Start from where you are currently reading": "Mulai dari tempat Anda sedang membaca",
"From Selection": "Dari Pilihan",
"Speed Reading Mode": "Mode Baca Cepat",
"Scroll left": "Gulir ke kiri",
"Scroll right": "Gulir ke kanan",
"Library Sync Progress": "Kemajuan Sinkronisasi Pustaka",
"Back to library": "Kembali ke perpustakaan",
"Group by...": "Kelompokkan menurut...",
"Export as Plain Text": "Ekspor sebagai Teks Biasa",
"Export as Markdown": "Ekspor sebagai Markdown",
"Show Page Navigation Buttons": "Tombol navigasi",
"Page {{number}}": "Halaman {{number}}",
"highlight": "sorotan",
"underline": "garis bawah",
"squiggly": "bergelombang",
"red": "merah",
"violet": "ungu",
"blue": "biru",
"green": "hijau",
"yellow": "kuning",
"Select {{style}} style": "Pilih gaya {{style}}",
"Select {{color}} color": "Pilih warna {{color}}",
"Close Book": "Tutup Buku",
"Speed Reading": "Membaca Cepat",
"Close Speed Reading": "Tutup Membaca Cepat",
"Authors": "Penulis",
"Books": "Buku",
"Groups": "Grup",
"Back to TTS Location": "Kembali ke Lokasi TTS",
"Metadata": "Metadata",
"Image viewer": "Penampil gambar",
"Previous Image": "Gambar Sebelumnya",
"Next Image": "Gambar Berikutnya",
"Zoomed": "Diperbesar",
"Zoom level": "Tingkat zoom",
"Table viewer": "Penampil tabel",
"Unable to connect to Readwise. Please check your network connection.": "Tidak dapat terhubung ke Readwise. Silakan periksa koneksi jaringan Anda.",
"Invalid Readwise access token": "Token akses Readwise tidak valid",
"Disconnected from Readwise": "Terputus dari Readwise",
"Never": "Tidak pernah",
"Readwise Settings": "Pengaturan Readwise",
"Connected to Readwise": "Terhubung ke Readwise",
"Last synced: {{time}}": "Terakhir disinkronkan: {{time}}",
"Sync Enabled": "Sinkronisasi Diaktifkan",
"Disconnect": "Putuskan sambungan",
"Connect your Readwise account to sync highlights.": "Hubungkan akun Readwise Anda untuk menyinkronkan sorotan.",
"Get your access token at": "Dapatkan token akses Anda di",
"Access Token": "Token Akses",
"Paste your Readwise access token": "Tempelkan token akses Readwise Anda",
"Config": "Konfigurasi",
"Readwise Sync": "Sinkronisasi Readwise",
"Push Highlights": "Kirim Sorotan",
"Highlights synced to Readwise": "Sorotan disinkronkan ke Readwise",
"Readwise sync failed: no internet connection": "Sinkronisasi Readwise gagal: tidak ada koneksi internet",
"Readwise sync failed: {{error}}": "Sinkronisasi Readwise gagal: {{error}}",
"System Screen Brightness": "Kecerahan Layar Sistem",
"Page:": "Halaman:",
"Page: {{number}}": "Halaman: {{number}}",
"Annotation page number": "Nomor halaman anotasi",
"Translating...": "Menerjemahkan...",
"Show Battery Percentage": "Tampilkan Persentase Baterai",
"Hide Scrollbar": "Sembunyikan Bilah Gulir",
"Skip to last reading position": "Lompat ke posisi baca terakhir",
"Show context": "Tampilkan konteks",
"Hide context": "Sembunyikan konteks",
"Decrease font size": "Perkecil ukuran font",
"Increase font size": "Perbesar ukuran font",
"Focus": "Fokus",
"Theme color": "Warna tema",
"Import failed": "Impor gagal",
"Available Formatters:": "Formatter Tersedia:",
"Format date": "Format tanggal",
"Markdown block quote (> per line)": "Kutipan blok Markdown (> per baris)",
"Newlines to <br>": "Baris baru ke <br>",
"Change case": "Ubah huruf besar/kecil",
"Trim whitespace": "Pangkas spasi",
"Truncate to n characters": "Potong ke n karakter",
"Replace text": "Ganti teks",
"Fallback value": "Nilai cadangan",
"Get length": "Dapatkan panjang",
"First/last element": "Elemen pertama/terakhir",
"Join array": "Gabungkan array",
"Backup failed: {{error}}": "Pencadangan gagal: {{error}}",
"Select Backup": "Pilih Cadangan",
"Restore failed: {{error}}": "Pemulihan gagal: {{error}}",
"Backup & Restore": "Cadangkan & Pulihkan",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "Buat cadangan perpustakaan Anda atau pulihkan dari cadangan sebelumnya. Pemulihan akan digabungkan dengan perpustakaan Anda saat ini.",
"Backup Library": "Cadangkan Perpustakaan",
"Restore Library": "Pulihkan Perpustakaan",
"Creating backup...": "Membuat cadangan...",
"Restoring library...": "Memulihkan perpustakaan...",
"{{current}} of {{total}} items": "{{current}} dari {{total}} item",
"Backup completed successfully!": "Pencadangan berhasil!",
"Restore completed successfully!": "Pemulihan berhasil!",
"Your library has been saved to the selected location.": "Perpustakaan Anda telah disimpan di lokasi yang dipilih.",
"{{added}} books added, {{updated}} books updated.": "{{added}} buku ditambahkan, {{updated}} buku diperbarui.",
"Operation failed": "Operasi gagal",
"Loading library...": "Memuat perpustakaan...",
"{{count}} books refreshed_other": "{{count}} buku diperbarui",
"Failed to refresh metadata": "Gagal memperbarui metadata",
"Refresh Metadata": "Perbarui Metadata",
"Keyboard Shortcuts": "Pintasan Keyboard",
"View all keyboard shortcuts": "Lihat semua pintasan keyboard",
"Switch Sidebar Tab": "Ganti tab bilah sisi",
"Toggle Notebook": "Tampilkan/sembunyikan buku catatan",
"Search in Book": "Cari di buku",
"Toggle Scroll Mode": "Alihkan mode gulir",
"Toggle Select Mode": "Alihkan mode pilih",
"Toggle Bookmark": "Alihkan penanda",
"Toggle Text to Speech": "Alihkan teks ke suara",
"Play / Pause TTS": "Putar / Jeda TTS",
"Toggle Paragraph Mode": "Alihkan mode paragraf",
"Highlight Selection": "Sorot pilihan",
"Underline Selection": "Garis bawahi pilihan",
"Annotate Selection": "Beri anotasi pilihan",
"Search Selection": "Cari pilihan",
"Copy Selection": "Salin pilihan",
"Translate Selection": "Terjemahkan pilihan",
"Dictionary Lookup": "Cari di kamus",
"Wikipedia Lookup": "Cari di Wikipedia",
"Read Aloud Selection": "Bacakan pilihan",
"Proofread Selection": "Periksa ejaan pilihan",
"Open Settings": "Buka pengaturan",
"Open Command Palette": "Buka palet perintah",
"Show Keyboard Shortcuts": "Tampilkan pintasan keyboard",
"Open Books": "Buka buku",
"Toggle Fullscreen": "Alihkan layar penuh",
"Close Window": "Tutup jendela",
"Quit App": "Keluar dari aplikasi",
"Go Left / Previous Page": "Ke kiri / Halaman sebelumnya",
"Go Right / Next Page": "Ke kanan / Halaman berikutnya",
"Go Up": "Ke atas",
"Go Down": "Ke bawah",
"Previous Chapter": "Bab sebelumnya",
"Next Chapter": "Bab berikutnya",
"Scroll Half Page Down": "Gulir setengah halaman ke bawah",
"Scroll Half Page Up": "Gulir setengah halaman ke atas",
"Save Note": "Simpan catatan",
"Single Section Scroll": "Gulir Satu Bagian",
"General": "Umum",
"Text to Speech": "Teks ke Suara",
"Zoom": "Zoom",
"Window": "Jendela",
"Your Bookshelf": "Rak Buku Anda",
"TTS": "Teks ke Suara",
"Media Info": "Info Media",
"Update Frequency": "Frekuensi Pembaruan",
"Every Sentence": "Setiap Kalimat",
"Every Paragraph": "Setiap Paragraf",
"Every Chapter": "Setiap Bab",
"TTS Media Info Update Frequency": "Frekuensi Pembaruan Info Media TTS",
"Select reading speed": "Pilih kecepatan membaca",
"Drag to seek": "Seret untuk mencari",
"Punctuation Delay": "Jeda tanda baca",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "Harap konfirmasi bahwa koneksi OPDS ini akan diteruskan melalui server Readest di aplikasi web sebelum melanjutkan.",
"Custom Headers": "Header Kustom",
"Custom Headers (optional)": "Header Kustom (opsional)",
"Add one header per line using \"Header-Name: value\".": "Tambahkan satu header per baris menggunakan \"Header-Name: value\".",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "Saya memahami bahwa koneksi OPDS ini akan diteruskan melalui server Readest di aplikasi web. Jika saya tidak mempercayai Readest dengan kredensial atau header ini, saya harus menggunakan aplikasi native.",
"Unable to connect to Hardcover. Please check your network connection.": "Tidak dapat terhubung ke Hardcover. Periksa koneksi jaringan Anda.",
"Invalid Hardcover API token": "Token API Hardcover tidak valid",
"Disconnected from Hardcover": "Terputus dari Hardcover",
"Hardcover Settings": "Pengaturan Hardcover",
"Connected to Hardcover": "Terhubung ke Hardcover",
"Connect your Hardcover account to sync reading progress and notes.": "Hubungkan akun Hardcover Anda untuk menyinkronkan progres membaca dan catatan.",
"Get your API token from hardcover.app → Settings → API.": "Dapatkan token API Anda dari hardcover.app → Pengaturan → API.",
"API Token": "Token API",
"Paste your Hardcover API token": "Tempel token API Hardcover Anda",
"Hardcover sync enabled for this book": "Sinkronisasi Hardcover diaktifkan untuk buku ini",
"Hardcover sync disabled for this book": "Sinkronisasi Hardcover dinonaktifkan untuk buku ini",
"Hardcover Sync": "Sinkronisasi Hardcover",
"Enable for This Book": "Aktifkan untuk Buku Ini",
"Push Notes": "Kirim Catatan",
"Enable Hardcover sync for this book first.": "Aktifkan sinkronisasi Hardcover untuk buku ini terlebih dahulu.",
"No annotations or excerpts to sync for this book.": "Tidak ada anotasi atau kutipan untuk disinkronkan pada buku ini.",
"Configure Hardcover in Settings first.": "Konfigurasikan Hardcover di Pengaturan terlebih dahulu.",
"No new Hardcover note changes to sync.": "Tidak ada perubahan catatan Hardcover baru untuk disinkronkan.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover disinkronkan: {{inserted}} baru, {{updated}} diperbarui, {{skipped}} tidak berubah",
"Hardcover notes sync failed: {{error}}": "Sinkronisasi catatan Hardcover gagal: {{error}}",
"Reading progress synced to Hardcover": "Progres membaca disinkronkan ke Hardcover",
"Hardcover progress sync failed: {{error}}": "Sinkronisasi progres Hardcover gagal: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "Pertahankan pengidentifikasi sumber yang ada",
"Toggle Toolbar": "Alihkan Bilah Alat"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Modalità automatica",
"Behavior": "Comportamento",
"Book": "Libro",
"Book Cover": "Copertina",
"Bookmark": "Segnalibro",
"Cancel": "Annulla",
"Chapter": "Capitolo",
@@ -46,7 +45,6 @@
"Horizontal Direction": "Direzione orizzontale",
"Hyphenation": "Sillabazione",
"Import Books": "Importa libri",
"Language:": "Lingua:",
"Layout": "Layout",
"Light Mode": "Modalità chiara",
"Loading...": "Caricamento...",
@@ -68,8 +66,8 @@
"Paging Animation": "Animazione cambio pagina",
"Paragraph": "Paragrafo",
"Parallel Read": "Lettura parallela",
"Published:": "Pubblicato:",
"Publisher:": "Editore:",
"Published": "Pubblicato",
"Publisher": "Editore",
"Reading Progress Synced": "Progresso lettura sincronizzato",
"Reload Page": "Ricarica pagina",
"Reveal in File Explorer": "Mostra in Esplora file",
@@ -83,7 +81,6 @@
"Search...": "Cerca...",
"Select Book": "Seleziona libro",
"Select Books": "Seleziona libri",
"Select Multiple Books": "Seleziona più libri",
"Sepia": "Seppia",
"Serif Font": "Font serif",
"Show Book Details": "Mostra dettagli libro",
@@ -94,23 +91,21 @@
"Slow": "Lento",
"Solarized": "Solarizzato",
"Speak": "Leggi",
"Subjects:": "Argomenti:",
"Subjects": "Argomenti",
"System Fonts": "Font di sistema",
"TTS not supported in this device": "TTS non supportato su questo dispositivo",
"Theme Color": "Colore tema",
"Theme Mode": "Modalità tema",
"Translate": "Traduci",
"Translated Text": "Testo tradotto",
"Unknown": "Sconosciuto",
"Untitled": "Senza titolo",
"Updated:": "Aggiornato:",
"Updated": "Aggiornato",
"Version {{version}}": "Versione {{version}}",
"Vertical Direction": "Direzione verticale",
"Welcome to your library. You can import your books here and read them anytime.": "Benvenuto nella tua biblioteca. Puoi importare i tuoi libri qui e leggerli in qualsiasi momento.",
"Wikipedia": "Wikipedia",
"Writing Mode": "Modalità scrittura",
"Your Library": "La tua biblioteca",
"TTS not supported for PDF": "TTS non supportato per PDF",
"Override Book Font": "Sovrascrivi font libro",
"Apply to All Books": "Applica a tutti i libri",
"Apply to This Book": "Applica a questo libro",
@@ -120,6 +115,7 @@
"Book Details": "Dettagli libro",
"From Local File": "Da file locale",
"TOC": "Sommario",
"Table of Contents": "Sommario",
"Book uploaded: {{title}}": "Libro caricato: {{title}}",
"Failed to upload book: {{title}}": "Caricamento libro non riuscito: {{title}}",
"Book downloaded: {{title}}": "Libro scaricato: {{title}}",
@@ -176,9 +172,6 @@
"Token": "Token",
"Your OTP token": "Il tuo token OTP",
"Verify token": "Verifica token",
"Sign in with Google": "Accedi con Google",
"Sign in with Apple": "Accedi con Apple",
"Sign in with GitHub": "Accedi con GitHub",
"Account": "Account",
"Failed to delete user. Please try again later.": "Impossibile eliminare l'utente. Riprova più tardi.",
"Community Support": "Supporto della community",
@@ -191,12 +184,11 @@
"RTL Direction": "Direzione RTL",
"Maximum Column Height": "Altezza massima colonna",
"Maximum Column Width": "Larghezza massima colonna",
"Continuous Scroll": "Scorrimento continuo",
"Fullscreen": "Schermo intero",
"No supported files found. Supported formats: {{formats}}": "Nessun file supportato trovato. Formati supportati: {{formats}}",
"Drop to Import Books": "Rilascia per importare libri",
"Custom": "Personalizzato",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Tutto il mondo è un palcoscenico,\nE tutti gli uomini e le donne sono solo attori;\nHanno le loro uscite e le loro entrate,\nE un uomo nella sua vita interpreta molte parti,\nI suoi atti sono sette età.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Tutto il mondo è un palcoscenico,\nE tutti gli uomini e le donne sono solo attori;\nHanno le loro uscite e le loro entrate,\nE un uomo nella sua vita interpreta molte parti,\nI suoi atti sono sette età.\n\n— William Shakespeare",
"Custom Theme": "Tema personalizzato",
"Theme Name": "Nome tema",
"Text Color": "Colore testo",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "Importazione automatica all'apertura del file",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "Nessun capitolo rilevato.",
"Failed to parse the EPUB file.": "Impossibile analizzare il file EPUB.",
"This book format is not supported.": "Questo formato di libro non è supportato.",
"No chapters detected": "Nessun capitolo rilevato",
"Failed to parse the EPUB file": "Impossibile analizzare il file EPUB",
"This book format is not supported": "Questo formato di libro non è supportato",
"Unable to fetch the translation. Please log in first and try again.": "Impossibile recuperare la traduzione. Accedi prima e riprova.",
"Group": "Gruppo",
"Always on Top": "Sempre in primo piano",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "Scaricando {{downloaded}} di {{contentLength}}",
"Download finished": "Download completato",
"DOWNLOAD & INSTALL": "SCARICA E INSTALLA",
"Changelog:": "Note di rilascio:",
"Changelog": "Note di rilascio",
"Software Update": "Aggiornamento software",
"Title": "Titolo",
"Date Read": "Data di lettura",
@@ -253,18 +245,15 @@
"Ascending": "Crescente",
"Descending": "Decrescente",
"Sort by...": "Ordina per...",
"Added:": "Aggiunto:",
"Format:": "Formato:",
"Added": "Aggiunto",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "Descrizione:",
"Description": "Descrizione",
"No description available": "Nessuna descrizione disponibile",
"List": "Elenco",
"Grid": "Griglia",
"(from 'As You Like It', Act II)": "(da 'Come vi piace', Atto II)",
"Link Color": "Colore link",
"Volume Keys for Page Flip": "Tasti volume per girare pagina",
"Clicks for Page Flip": "Clic per girare pagina",
"Swap Clicks Area": "Inverti area dei clic",
"Screen": "Schermo",
"Orientation": "Orientamento",
"Portrait": "Ritratto",
@@ -273,7 +262,7 @@
"Checking for updates...": "Controllo aggiornamenti...",
"Error checking for updates": "Errore durante il controllo degli aggiornamenti",
"Details": "Dettagli",
"File Size:": "Dimensione file:",
"File Size": "Dimensione file",
"Auto Detect": "Rilevamento automatico",
"Next Section": "Sezione successiva",
"Previous Section": "Sezione precedente",
@@ -301,7 +290,6 @@
"Disable Translation": "Disabilita traduzione",
"Scroll": "Scorri",
"Overlap Pixels": "Pixel di sovrapposizione",
"Click": "Fai clic",
"System Language": "Lingua di sistema",
"Security": "Security",
"Allow JavaScript": "Consenti JavaScript",
@@ -316,7 +304,6 @@
"Synced at {{time}}": "Sincronizzato alle {{time}}",
"Never synced": "Mai sincronizzato",
"Show Remaining Time": "Mostra tempo rimanente",
"Show Page Number": "Mostra numero pagina",
"{{time}} min left in chapter": "{{time}} min rimasti nel capitolo",
"Override Book Color": "Override colore libro",
"Login Required": "Accesso richiesto",
@@ -340,7 +327,6 @@
"Left Margin (px)": "Margine Sinistro (px)",
"Column Gap (%)": "Spazio tra Colonne (%)",
"Always Show Status Bar": "Mostra sempre la barra di stato",
"Translation Not Available": "Traduzione non disponibile",
"Custom Content CSS": "CSS contenuto",
"Enter CSS for book content styling...": "Inserisci il CSS per il contenuto del libro...",
"Custom Reader UI CSS": "CSS interfaccia",
@@ -350,12 +336,12 @@
"Fit": "Adatta",
"Reset {{settings}}": "Reimposta {{settings}}",
"Reset Settings": "Reimposta impostazioni",
"{{count}} pages left in chapter_one": "{{count}} pagina rimasta nel capitolo",
"{{count}} pages left in chapter_many": "{{count}} pagine rimaste nel capitolo",
"{{count}} pages left in chapter_other": "{{count}} pagine rimaste nel capitolo",
"{{count}} pages left in chapter_one": "<0>{{count}}</0><1> pagina rimasta nel capitolo</1>",
"{{count}} pages left in chapter_many": "<0>{{count}}</0><1> pagine rimaste nel capitolo</1>",
"{{count}} pages left in chapter_other": "<0>{{count}}</0><1> pagine rimaste nel capitolo</1>",
"Show Remaining Pages": "Mostra pagine rimanenti",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Gestisci Abbonamento",
"Coming Soon": "Prossimamente",
@@ -363,7 +349,6 @@
"Upgrade to Plus or Pro": "Aggiorna a Plus o Pro",
"Current Plan": "Piano Attuale",
"Plan Limits": "Limiti del Piano",
"Failed to manage subscription. Please try again later.": "Impossibile gestire l'abbonamento. Riprova più tardi.",
"Processing your payment...": "Elaborazione del pagamento...",
"Please wait while we confirm your subscription.": "Attendi mentre confermiamo il tuo abbonamento.",
"Payment Processing": "Elaborazione Pagamento",
@@ -376,7 +361,6 @@
"Email:": "Email:",
"Plan:": "Piano:",
"Amount:": "Importo:",
"Subscription ID:": "ID Abbonamento:",
"Go to Library": "Vai alla Libreria",
"Need help? Contact our support team at support@readest.com": "Hai bisogno di aiuto? Contatta il nostro supporto a support@readest.com",
"Free Plan": "Piano Gratuito",
@@ -405,7 +389,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "Ascolta senza limiti quanto vuoi.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Sblocca traduzioni avanzate e più utilizzo giornaliero.",
"DeepL Pro Access": "Accesso DeepL Pro",
"2 GB Cloud Sync Storage": "2 GB di Archiviazione Cloud",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Ricevi supporto prioritario quando serve.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Quota giornaliera esaurita. Passa a un piano superiore per continuare.",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Traduci qualsiasi testo istantaneamente con la potenza di Google, Azure o DeepL—comprendi contenuti in qualsiasi lingua.",
@@ -416,10 +399,802 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Sfrutta potenti strumenti AI per lettura intelligente, traduzione e scoperta di contenuti.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Traduci fino a 100.000 caratteri al giorno con il motore di traduzione più accurato.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Traduci fino a 500.000 caratteri al giorno con il motore di traduzione più accurato.",
"10 GB Cloud Sync Storage": "Archiviazione Cloud Sync da 10 GB",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "Archivia e accedi in sicurezza alla tua intera collezione di lettura con fino a 2 GB di storage cloud.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "Archivia e accedi in sicurezza alla tua intera collezione di lettura con fino a 10 GB di storage cloud.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Archivia e accedi in sicurezza alla tua intera collezione di lettura con fino a 5 GB di storage cloud.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Archivia e accedi in sicurezza alla tua intera collezione di lettura con fino a 20 GB di storage cloud.",
"Deleted cloud backup of the book: {{title}}": "Backup cloud del libro eliminato: {{title}}",
"Failed to delete cloud backup of the book": "Impossibile eliminare il backup cloud del libro",
"Are you sure to delete the cloud backup of the selected book?": "Sei sicuro di voler eliminare il backup cloud del libro selezionato?"
"Are you sure to delete the cloud backup of the selected book?": "Sei sicuro di voler eliminare il backup cloud del libro selezionato?",
"What's New in Readest": "Novità in Readest",
"Enter book title": "Inserisci il titolo del libro",
"Subtitle": "Sottotitolo",
"Enter book subtitle": "Inserisci il sottotitolo del libro",
"Enter author name": "Inserisci il nome dell'autore",
"Series": "Serie",
"Enter series name": "Inserisci il nome della serie",
"Series Index": "Numero della serie",
"Enter series index": "Inserisci il numero della serie",
"Total in Series": "Totale nella serie",
"Enter total books in series": "Inserisci il numero totale di libri nella serie",
"Enter publisher": "Inserisci l'editore",
"Publication Date": "Data di pubblicazione",
"Identifier": "Identificatore",
"Enter book description": "Inserisci la descrizione del libro",
"Change cover image": "Cambia immagine di copertina",
"Replace": "Sostituisci",
"Unlock cover": "Sblocca copertina",
"Lock cover": "Blocca copertina",
"Auto-Retrieve Metadata": "Recupera metadati automaticamente",
"Auto-Retrieve": "Recupero automatico",
"Unlock all fields": "Sblocca tutti i campi",
"Unlock All": "Sblocca tutto",
"Lock all fields": "Blocca tutti i campi",
"Lock All": "Blocca tutto",
"Reset": "Ripristina",
"Edit Metadata": "Modifica metadati",
"Locked": "Bloccato",
"Select Metadata Source": "Seleziona fonte metadati",
"Keep manual input": "Mantieni input manuale",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Narrativa, Scienza, Storia",
"Open Book in New Window": "Apri libro in una nuova finestra",
"Voices for {{lang}}": "Voci per {{lang}}",
"Yandex Translate": "Yandex Translate",
"YYYY or YYYY-MM-DD": "AAAA o AAAA-MM-GG",
"Restore Purchase": "Ripristina acquisto",
"No purchases found to restore.": "Nessun acquisto trovato da ripristinare.",
"Failed to restore purchases.": "Impossibile ripristinare gli acquisti.",
"Failed to manage subscription.": "Impossibile gestire l'abbonamento.",
"Failed to load subscription plans.": "Impossibile caricare i piani di abbonamento.",
"year": "anno",
"Failed to create checkout session": "Impossibile creare la sessione di checkout",
"Storage": "Archiviazione",
"Terms of Service": "Termini di servizio",
"Privacy Policy": "Informativa sulla privacy",
"Disable Double Click": "Disabilita Doppio Clic",
"TTS not supported for this document": "TTS non supportato per questo documento",
"Reset Password": "Reimposta Password",
"Show Reading Progress": "Mostra Progresso Lettura",
"Reading Progress Style": "Stile di Progresso Lettura",
"Page Number": "Numero di Pagina",
"Percentage": "Percentuale",
"Deleted local copy of the book: {{title}}": "Copie locale del libro eliminata: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Impossibile eliminare il backup cloud del libro: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Impossibile eliminare la copia locale del libro: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Sei sicuro di voler eliminare la copia locale del libro selezionato?",
"Remove from Cloud & Device": "Rimuovi da Cloud & Dispositivo",
"Remove from Cloud Only": "Rimuovi solo da Cloud",
"Remove from Device Only": "Rimuovi solo da Dispositivo",
"Disconnected": "Disconnesso",
"KOReader Sync Settings": "Impostazioni di Sincronizzazione KOReader",
"Sync Strategy": "Strategia di Sincronizzazione",
"Ask on conflict": "Chiedi in caso di conflitto",
"Always use latest": "Usa sempre l'ultima versione",
"Send changes only": "Invia solo le modifiche",
"Receive changes only": "Ricevi solo le modifiche",
"Checksum Method": "Metodo di Controllo",
"File Content (recommended)": "Contenuto del File (consigliato)",
"File Name": "Nome del File",
"Device Name": "Nome del Dispositivo",
"Connect to your KOReader Sync server.": "Connettiti al tuo server KOReader Sync.",
"Server URL": "URL del Server",
"Username": "Nome Utente",
"Your Username": "Il tuo Nome Utente",
"Password": "Password",
"Connect": "Connetti",
"KOReader Sync": "KOReader Sync",
"Sync Conflict": "Conflitto di Sincronizzazione",
"Sync reading progress from \"{{deviceName}}\"?": "Sincronizzare il progresso di lettura da \"{{deviceName}}\"?",
"another device": "un altro dispositivo",
"Local Progress": "Progresso Locale",
"Remote Progress": "Progresso Remoto",
"Page {{page}} of {{total}} ({{percentage}}%)": "Pagina {{page}} di {{total}} ({{percentage}}%)",
"Current position": "Posizione Corrente",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Circa pagina {{page}} di {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Circa {{percentage}}%",
"Failed to connect": "Impossibile connettersi",
"Sync Server Connected": "Server di sincronizzazione connesso",
"Sync as {{userDisplayName}}": "Sincronizza come {{userDisplayName}}",
"Custom Fonts": "Font Personalizzati",
"Cancel Delete": "Annulla Eliminazione",
"Import Font": "Importa Font",
"Delete Font": "Elimina Font",
"Tips": "Suggerimenti",
"Custom fonts can be selected from the Font Face menu": "I font personalizzati possono essere selezionati dal menu Carattere",
"Manage Custom Fonts": "Gestisci Font Personalizzati",
"Select Files": "Seleziona File",
"Select Image": "Seleziona Immagine",
"Select Video": "Seleziona Video",
"Select Audio": "Seleziona Audio",
"Select Fonts": "Seleziona Font",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Formati di font supportati: .ttf, .otf, .woff, .woff2",
"Push Progress": "Progresso push",
"Pull Progress": "Progresso pull",
"Previous Paragraph": "Paragrafo precedente",
"Previous Sentence": "Frase precedente",
"Pause": "Pausa",
"Play": "Riproduci",
"Next Sentence": "Frase successiva",
"Next Paragraph": "Paragrafo successivo",
"Separate Cover Page": "Pagina di copertina separata",
"Resize Notebook": "Ridimensiona quaderno",
"Resize Sidebar": "Ridimensiona barra laterale",
"Get Help from the Readest Community": "Ottieni aiuto dalla community di Readest",
"Remove cover image": "Rimuovi immagine di copertina",
"Bookshelf": "Scaffale dei libri",
"View Menu": "Visualizza menu",
"Settings Menu": "Menu impostazioni",
"View account details and quota": "Visualizza dettagli account e quota",
"Library Header": "Intestazione biblioteca",
"Book Content": "Contenuto del libro",
"Footer Bar": "Barra piè di pagina",
"Header Bar": "Barra intestazione",
"View Options": "Opzioni di visualizzazione",
"Book Menu": "Menu libro",
"Search Options": "Opzioni di ricerca",
"Close": "Chiudi",
"Delete Book Options": "Opzioni di eliminazione libro",
"ON": "ATTIVO",
"OFF": "DISATTIVO",
"Reading Progress": "Progresso di lettura",
"Page Margin": "Margine di pagina",
"Remove Bookmark": "Rimuovi Segnalibro",
"Add Bookmark": "Aggiungi Segnalibro",
"Books Content": "Contenuto dei Libri",
"Jump to Location": "Salta alla Posizione",
"Unpin Notebook": "Sblocca Quaderno",
"Pin Notebook": "Blocca Quaderno",
"Hide Search Bar": "Nascondi Barra di Ricerca",
"Show Search Bar": "Mostra Barra di Ricerca",
"On {{current}} of {{total}} page": "A pagina {{current}} di {{total}}",
"Section Title": "Titolo Sezione",
"Decrease": "Diminuisci",
"Increase": "Aumenta",
"Settings Panels": "Pannelli di Impostazione",
"Settings": "Impostazioni",
"Unpin Sidebar": "Sblocca Bilah Samping",
"Pin Sidebar": "Blocca Bilah Samping",
"Toggle Sidebar": "Toggel Bilah Samping",
"Toggle Translation": "Toggel Terjemahan",
"Translation Disabled": "Terjemahan Dinonaktifkan",
"Minimize": "Minimalkan",
"Maximize or Restore": "Maksimalkan atau Pulihkan",
"Exit Parallel Read": "Esci dalla lettura parallela",
"Enter Parallel Read": "Entra nella lettura parallela",
"Zoom Level": "Livello di zoom",
"Zoom Out": "Riduci zoom",
"Reset Zoom": "Ripristina zoom",
"Zoom In": "Inganna zoom",
"Zoom Mode": "Modalità zoom",
"Single Page": "Pagina singola",
"Auto Spread": "Distribuzione automatica",
"Fit Page": "Adatta pagina",
"Fit Width": "Adatta larghezza",
"Failed to select directory": "Impossibile selezionare la directory",
"The new data directory must be different from the current one.": "La nuova directory dei dati deve essere diversa da quella attuale.",
"Migration failed: {{error}}": "Migrzione fallita: {{error}}",
"Change Data Location": "Cambia posizione dei dati",
"Current Data Location": "Posizione attuale dei dati",
"Total size: {{size}}": "Dimensione totale: {{size}}",
"Calculating file info...": "Calcolo informazioni file...",
"New Data Location": "Nuova posizione dei dati",
"Choose Different Folder": "Scegli una cartella diversa",
"Choose New Folder": "Scegli una nuova cartella",
"Migrating data...": "Migrando dati...",
"Copying: {{file}}": "Copia in corso: {{file}}",
"{{current}} of {{total}} files": "{{current}} di {{total}} file",
"Migration completed successfully!": "Migrzione completata con successo!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "I tuoi dati sono stati spostati nella nuova posizione. Riavvia l'applicazione per completare il processo.",
"Migration failed": "Migrzione fallita",
"Important Notice": "Avviso Importante",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Questo sposterà tutti i dati dell'app nella nuova posizione. Assicurati che la destinazione abbia spazio libero sufficiente.",
"Restart App": "Riavvia App",
"Start Migration": "Inizia Migrazione",
"Advanced Settings": "Impostazioni Avanzate",
"File count: {{size}}": "Conteggio file: {{size}}",
"Background Read Aloud": "Riproduzione in background",
"Ready to read aloud": "Pronto per la lettura ad alta voce",
"Read Aloud": "Leggi ad alta voce",
"Screen Brightness": "Luminosità dello schermo",
"Background Image": "Immagine di sfondo",
"Import Image": "Importa immagine",
"Opacity": "Opacità",
"Size": "Dimensione",
"Cover": "Copertura",
"Contain": "Contenere",
"{{number}} pages left in chapter": "<0>{{number}}</0><1> pagine rimaste nel capitolo</1>",
"Device": "Dispositivo",
"E-Ink Mode": "Modalità E-Ink",
"Highlight Colors": "Colori Evidenziazione",
"Pagination": "Impaginazione",
"Disable Double Tap": "Disabilita Doppio Tap",
"Tap to Paginate": "Tocca per Impaginare",
"Click to Paginate": "Clicca per Impaginare",
"Tap Both Sides": "Tocca Entrambi i Lati",
"Click Both Sides": "Clicca Entrambi i Lati",
"Swap Tap Sides": "Scambia Sides Tap",
"Swap Click Sides": "Scambia Sides Click",
"Source and Translated": "Fonte e Tradotto",
"Translated Only": "Solo Tradotto",
"Source Only": "Solo Fonte",
"TTS Text": "Testo TTS",
"The book file is corrupted": "Il file del libro è danneggiato",
"The book file is empty": "Il file del libro è vuoto",
"Failed to open the book file": "Impossibile aprire il file del libro",
"On-Demand Purchase": "Acquisto su Richiesta",
"Full Customization": "Personalizzazione Completa",
"Lifetime Plan": "Piano a Vita",
"One-Time Payment": "Pagamento Una Tantum",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Effettua un pagamento una tantum per godere dell'accesso a vita a funzionalità specifiche su tutti i dispositivi. Acquista funzionalità o servizi specifici solo quando ne hai bisogno.",
"Expand Cloud Sync Storage": "Espandi Spazio di Archiviazione Cloud",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Espandi il tuo spazio di archiviazione cloud per sempre con un acquisto una tantum. Ogni acquisto aggiuntivo aumenta lo spazio.",
"Unlock All Customization Options": "Sblocca Tutte le Opzioni di Personalizzazione",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Sblocca temi aggiuntivi, font, opzioni di layout e lettura ad alta voce, traduttori, servizi di archiviazione cloud.",
"Purchase Successful!": "Acquisto Riuscito!",
"lifetime": "a vita",
"Thank you for your purchase! Your payment has been processed successfully.": "Grazie per il tuo acquisto! Il pagamento è stato elaborato con successo.",
"Order ID:": "ID Ordine:",
"TTS Highlighting": "Evidenziazione TTS",
"Style": "Stile",
"Underline": "Sottolineato",
"Strikethrough": "Barrato",
"Squiggly": "Ondulato",
"Outline": "Contorno",
"Save Current Color": "Salva Colore Corrente",
"Quick Colors": "Colori Veloci",
"Highlighter": "Evidenziatore",
"Save Book Cover": "Salva Copertina del Libro",
"Auto-save last book cover": "Salva automaticamente l'ultima copertina del libro",
"Back": "Indietro",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Email di conferma inviata! Controlla il tuo vecchio e nuovo indirizzo email per confermare la modifica.",
"Failed to update email": "Aggiornamento dell'email non riuscito",
"New Email": "Nuova email",
"Your new email": "La tua nuova email",
"Updating email ...": "Aggiornamento dell'email ...",
"Update email": "Aggiorna email",
"Current email": "Email attuale",
"Update Email": "Aggiorna email",
"All": "Tutti",
"Unable to open book": "Impossibile aprire il libro",
"Punctuation": "Segni di punteggiatura",
"Replace Quotation Marks": "Sostituisci le virgolette",
"Enabled only in vertical layout.": "Abilitato solo in layout verticale.",
"No Conversion": "Nessuna conversione",
"Simplified to Traditional": "Semplificato → Tradizionale",
"Traditional to Simplified": "Tradizionale → Semplificato",
"Simplified to Traditional (Taiwan)": "Semplificato → Tradizionale (Taiwan)",
"Simplified to Traditional (Hong Kong)": "Semplificato → Tradizionale (Hong Kong)",
"Simplified to Traditional (Taiwan), with phrases": "Semplificato → Tradizionale (Taiwan • frasi)",
"Traditional (Taiwan) to Simplified": "Tradizionale (Taiwan) → Semplificato",
"Traditional (Hong Kong) to Simplified": "Tradizionale (Hong Kong) → Semplificato",
"Traditional (Taiwan) to Simplified, with phrases": "Tradizionale (Taiwan • frasi) → Semplificato",
"Convert Simplified and Traditional Chinese": "Converti Cinese Semplificato/Tradizionale",
"Convert Mode": "Modalità conversione",
"Failed to auto-save book cover for lock screen: {{error}}": "Impossibile salvare automaticamente la copertina del libro per la schermata di blocco: {{error}}",
"Download from Cloud": "Scarica dal Cloud",
"Upload to Cloud": "Carica sul Cloud",
"Clear Custom Fonts": "Pulisci Font Personalizzati",
"Columns": "Colonne",
"OPDS Catalogs": "Cataloghi OPDS",
"Adding LAN addresses is not supported in the web app version.": "L'aggiunta di indirizzi LAN non è supportata nella versione web.",
"Invalid OPDS catalog. Please check the URL.": "Catalogo OPDS non valido. Controlla l'URL.",
"Browse and download books from online catalogs": "Sfoglia e scarica libri dai cataloghi online",
"My Catalogs": "I miei cataloghi",
"Add Catalog": "Aggiungi catalogo",
"No catalogs yet": "Nessun catalogo",
"Add your first OPDS catalog to start browsing books": "Aggiungi il tuo primo catalogo OPDS per iniziare a sfogliare i libri",
"Add Your First Catalog": "Aggiungi il tuo primo catalogo",
"Browse": "Sfoglia",
"Popular Catalogs": "Cataloghi popolari",
"Add": "Aggiungi",
"Add OPDS Catalog": "Aggiungi catalogo OPDS",
"Catalog Name": "Nome del catalogo",
"My Calibre Library": "La mia libreria Calibre",
"OPDS URL": "URL OPDS",
"Username (optional)": "Username (opzionale)",
"Password (optional)": "Password (opzionale)",
"Description (optional)": "Descrizione (opzionale)",
"A brief description of this catalog": "Breve descrizione del catalogo",
"Validating...": "Convalida in corso...",
"View All": "Vedi tutto",
"Forward": "Avanti",
"Home": "Home",
"{{count}} items_one": "{{count}} elemento",
"{{count}} items_many": "{{count}} elementi",
"{{count}} items_other": "{{count}} elementi",
"Download completed": "Download completato",
"Download failed": "Download non riuscito",
"Open Access": "Accesso libero",
"Borrow": "Prendi in prestito",
"Buy": "Acquista",
"Subscribe": "Abbonati",
"Sample": "Anteprima",
"Download": "Scarica",
"Open & Read": "Apri e leggi",
"Tags": "Tag",
"Tag": "Tag",
"First": "Primo",
"Previous": "Precedente",
"Next": "Successivo",
"Last": "Ultimo",
"Cannot Load Page": "Impossibile caricare la pagina",
"An error occurred": "Si è verificato un errore",
"Online Library": "Libreria online",
"URL must start with http:// or https://": "URL deve iniziare con http:// o https://",
"Title, Author, Tag, etc...": "Titolo, Autore, Tag, ecc...",
"Query": "Query",
"Subject": "Soggetto",
"Enter {{terms}}": "Inserisci {{terms}}",
"No search results found": "Nessun risultato di ricerca trovato",
"Failed to load OPDS feed: {{status}} {{statusText}}": "Impossibile caricare il feed OPDS: {{status}} {{statusText}}",
"Search in {{title}}": "Cerca in {{title}}",
"Manage Storage": "Gestisci archiviazione",
"Failed to load files": "Impossibile caricare i file",
"Deleted {{count}} file(s)_one": "È stato eliminato {{count}} file",
"Deleted {{count}} file(s)_many": "Sono stati eliminati {{count}} file",
"Deleted {{count}} file(s)_other": "Sono stati eliminati {{count}} file",
"Failed to delete {{count}} file(s)_one": "Impossibile eliminare {{count}} file",
"Failed to delete {{count}} file(s)_many": "Impossibile eliminare {{count}} file",
"Failed to delete {{count}} file(s)_other": "Impossibile eliminare {{count}} file",
"Failed to delete files": "Impossibile eliminare i file",
"Total Files": "File totali",
"Total Size": "Dimensione totale",
"Quota": "Quota",
"Used": "Utilizzato",
"Files": "File",
"Search files...": "Cerca file...",
"Newest First": "Più recenti",
"Oldest First": "Più vecchi",
"Largest First": "Più grandi",
"Smallest First": "Più piccoli",
"Name A-Z": "Nome A-Z",
"Name Z-A": "Nome Z-A",
"{{count}} selected_one": "{{count}} selezionato",
"{{count}} selected_many": "{{count}} selezionati",
"{{count}} selected_other": "{{count}} selezionati",
"Delete Selected": "Elimina selezionati",
"Created": "Creato",
"No files found": "Nessun file trovato",
"No files uploaded yet": "Nessun file caricato",
"files": "file",
"Page {{current}} of {{total}}": "Pagina {{current}} di {{total}}",
"Are you sure to delete {{count}} selected file(s)?_one": "Sei sicuro di voler eliminare {{count}} file selezionato?",
"Are you sure to delete {{count}} selected file(s)?_many": "Sei sicuro di voler eliminare {{count}} file selezionati?",
"Are you sure to delete {{count}} selected file(s)?_other": "Sei sicuro di voler eliminare {{count}} file selezionati?",
"Cloud Storage Usage": "Utilizzo archiviazione cloud",
"Rename Group": "Rinomina gruppo",
"From Directory": "Da directory",
"Successfully imported {{count}} book(s)_one": "Importato con successo 1 libro",
"Successfully imported {{count}} book(s)_many": "Importati con successo {{count}} libri",
"Successfully imported {{count}} book(s)_other": "Importati con successo {{count}} libri",
"Count": "Conteggio",
"Start Page": "Pagina iniziale",
"Search in OPDS Catalog...": "Cerca nel catalogo OPDS...",
"Please log in to use advanced TTS features": "Effettua il login per utilizzare le funzionalità TTS avanzate",
"Word limit of 30 words exceeded.": "È stato superato il limite di 30 parole.",
"Proofread": "Revisione",
"Current selection": "Selezione corrente",
"All occurrences in this book": "Tutte le occorrenze in questo libro",
"All occurrences in your library": "Tutte le occorrenze nella tua libreria",
"Selected text:": "Testo selezionato:",
"Replace with:": "Sostituisci con:",
"Enter text...": "Inserisci testo…",
"Case sensitive:": "Maiuscole/minuscole:",
"Scope:": "Ambito:",
"Selection": "Selezione",
"Library": "Libreria",
"Yes": "Sì",
"No": "No",
"Proofread Replacement Rules": "Regole di sostituzione per la revisione",
"Selected Text Rules": "Regole per il testo selezionato",
"No selected text replacement rules": "Nessuna regola di sostituzione per il testo selezionato",
"Book Specific Rules": "Regole specifiche del libro",
"No book-level replacement rules": "Nessuna regola di sostituzione a livello di libro",
"Disable Quick Action": "Disattiva azione rapida",
"Enable Quick Action on Selection": "Attiva azione rapida sulla selezione",
"None": "Nessuno",
"Annotation Tools": "Strumenti di annotazione",
"Enable Quick Actions": "Attiva azioni rapide",
"Quick Action": "Azione rapida",
"Copy to Notebook": "Copia nel taccuino",
"Copy text after selection": "Copia testo dopo la selezione",
"Highlight text after selection": "Evidenzia testo dopo la selezione",
"Annotate text after selection": "Annota testo dopo la selezione",
"Search text after selection": "Cerca testo dopo la selezione",
"Look up text in dictionary after selection": "Cerca testo nel dizionario dopo la selezione",
"Look up text in Wikipedia after selection": "Cerca testo in Wikipedia dopo la selezione",
"Translate text after selection": "Traduci testo dopo la selezione",
"Read text aloud after selection": "Leggi ad alta voce il testo dopo la selezione",
"Proofread text after selection": "Correggi il testo dopo la selezione",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} attivi, {{pendingCount}} in attesa",
"{{failedCount}} failed": "{{failedCount}} falliti",
"Waiting...": "In attesa...",
"Failed": "Fallito",
"Completed": "Completato",
"Cancelled": "Annullato",
"Retry": "Riprova",
"Active": "Attivi",
"Transfer Queue": "Coda trasferimenti",
"Upload All": "Carica tutti",
"Download All": "Scarica tutti",
"Resume Transfers": "Riprendi trasferimenti",
"Pause Transfers": "Sospendi trasferimenti",
"Pending": "In attesa",
"No transfers": "Nessun trasferimento",
"Retry All": "Riprova tutti",
"Clear Completed": "Cancella completati",
"Clear Failed": "Cancella falliti",
"Upload queued: {{title}}": "Caricamento in coda: {{title}}",
"Download queued: {{title}}": "Download in coda: {{title}}",
"Book not found in library": "Libro non trovato nella libreria",
"Unknown error": "Errore sconosciuto",
"Please log in to continue": "Accedi per continuare",
"Cloud File Transfers": "Trasferimenti file cloud",
"Show Search Results": "Mostra risultati",
"Search results for '{{term}}'": "Risultati per '{{term}}'",
"Close Search": "Chiudi ricerca",
"Previous Result": "Risultato precedente",
"Next Result": "Risultato successivo",
"Bookmarks": "Segnalibri",
"Annotations": "Annotazioni",
"Show Results": "Mostra risultati",
"Clear search": "Cancella ricerca",
"Clear search history": "Cancella cronologia ricerche",
"Tap to Toggle Footer": "Tocca per mostrare/nascondere il piè di pagina",
"Show Current Time": "Mostra ora attuale",
"Use 24 Hour Clock": "Usa formato 24 ore",
"Show Current Battery Status": "Mostra lo stato attuale della batteria",
"Exported successfully": "Esportato con successo",
"Book exported successfully.": "Libro esportato con successo.",
"Failed to export the book.": "Impossibile esportare il libro.",
"Export Book": "Esporta libro",
"Whole word:": "Parola intera:",
"Error": "Errore",
"Unable to load the article. Try searching directly on {{link}}.": "Impossibile caricare l'articolo. Prova a cercare direttamente su {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Impossibile caricare la parola. Prova a cercare direttamente su {{link}}.",
"Date Published": "Data di pubblicazione",
"Only for TTS:": "Solo per TTS:",
"Uploaded": "Caricato",
"Downloaded": "Scaricato",
"Deleted": "Eliminato",
"Note:": "Nota:",
"Time:": "Ora:",
"Format Options": "Opzioni formato",
"Export Date": "Data esportazione",
"Chapter Titles": "Titoli capitoli",
"Chapter Separator": "Separatore capitoli",
"Highlights": "Evidenziazioni",
"Note Date": "Data nota",
"Advanced": "Avanzate",
"Hide": "Nascondi",
"Show": "Mostra",
"Use Custom Template": "Usa modello personalizzato",
"Export Template": "Modello esportazione",
"Template Syntax:": "Sintassi modello:",
"Insert value": "Inserisci valore",
"Format date (locale)": "Formatta data (locale)",
"Format date (custom)": "Formatta data (personalizzato)",
"Conditional": "Condizionale",
"Loop": "Ciclo",
"Available Variables:": "Variabili disponibili:",
"Book title": "Titolo libro",
"Book author": "Autore libro",
"Export date": "Data esportazione",
"Array of chapters": "Elenco capitoli",
"Chapter title": "Titolo capitolo",
"Array of annotations": "Elenco annotazioni",
"Highlighted text": "Testo evidenziato",
"Annotation note": "Nota annotazione",
"Date Format Tokens:": "Token formato data:",
"Year (4 digits)": "Anno (4 cifre)",
"Month (01-12)": "Mese (01-12)",
"Day (01-31)": "Giorno (01-31)",
"Hour (00-23)": "Ora (00-23)",
"Minute (00-59)": "Minuto (00-59)",
"Second (00-59)": "Secondo (00-59)",
"Show Source": "Mostra sorgente",
"No content to preview": "Nessun contenuto da visualizzare",
"Export": "Esporta",
"Set Timeout": "Imposta timeout",
"Select Voice": "Seleziona voce",
"Toggle Sticky Bottom TTS Bar": "Attiva/disattiva barra TTS fissa",
"Display what I'm reading on Discord": "Mostra cosa sto leggendo su Discord",
"Show on Discord": "Mostra su Discord",
"Instant {{action}}": "{{action}} istantaneo",
"Instant {{action}} Disabled": "{{action}} istantaneo disattivato",
"Annotation": "Annotazione",
"Reset Template": "Reimposta modello",
"Annotation style": "Stile annotazione",
"Annotation color": "Colore annotazione",
"Annotation time": "Ora annotazione",
"AI": "IA",
"Are you sure you want to re-index this book?": "Sei sicuro di voler reindicizzare questo libro?",
"Enable AI in Settings": "Abilita IA nelle impostazioni",
"Index This Book": "Indicizza questo libro",
"Enable AI search and chat for this book": "Abilita ricerca IA e chat per questo libro",
"Start Indexing": "Avvia indicizzazione",
"Indexing book...": "Indicizzazione libro...",
"Preparing...": "Preparazione...",
"Delete this conversation?": "Eliminare questa conversazione?",
"No conversations yet": "Ancora nessuna conversazione",
"Start a new chat to ask questions about this book": "Avvia una nuova chat per fare domande su questo libro",
"Rename": "Rinomina",
"New Chat": "Nuova chat",
"Chat": "Chat",
"Please enter a model ID": "Inserisci un ID modello",
"Model not available or invalid": "Modello non disponibile o non valido",
"Failed to validate model": "Validazione modello fallita",
"Couldn't connect to Ollama. Is it running?": "Impossibile connettersi a Ollama. È in esecuzione?",
"Invalid API key or connection failed": "Chiave API non valida o connessione fallita",
"Connection failed": "Connessione fallita",
"AI Assistant": "Assistente IA",
"Enable AI Assistant": "Abilita assistente IA",
"Provider": "Fornitore",
"Ollama (Local)": "Ollama (Locale)",
"AI Gateway (Cloud)": "Gateway IA (Cloud)",
"Ollama Configuration": "Configurazione Ollama",
"Refresh Models": "Aggiorna modelli",
"AI Model": "Modello IA",
"No models detected": "Nessun modello rilevato",
"AI Gateway Configuration": "Configurazione gateway IA",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Scegli tra una selezione di modelli IA di alta qualità ed economici. Puoi anche usare il tuo modello selezionando \"Modello personalizzato\" qui sotto.",
"API Key": "Chiave API",
"Get Key": "Ottieni chiave",
"Model": "Modello",
"Custom Model...": "Modello personalizzato...",
"Custom Model ID": "ID modello personalizzato",
"Validate": "Convalida",
"Model available": "Modello disponibile",
"Connection": "Connessione",
"Test Connection": "Testa connessione",
"Connected": "Connesso",
"Custom Colors": "Colori personalizzati",
"Color E-Ink Mode": "Modalità E-Ink a colori",
"Reading Ruler": "Righello di lettura",
"Enable Reading Ruler": "Abilita righello di lettura",
"Lines to Highlight": "Righe da evidenziare",
"Ruler Color": "Colore del righello",
"Command Palette": "Tavolozza dei comandi",
"Search settings and actions...": "Cerca impostazioni e azioni...",
"No results found for": "Nessun risultato trovato per",
"Type to search settings and actions": "Digita per cercare impostazioni e azioni",
"Recent": "Recenti",
"navigate": "naviga",
"select": "seleziona",
"close": "chiudi",
"Search Settings": "Cerca impostazioni",
"Page Margins": "Margini della pagina",
"AI Provider": "Fornitore AI",
"Ollama URL": "URL Ollama",
"Ollama Model": "Modello Ollama",
"AI Gateway Model": "Modello AI Gateway",
"Actions": "Azioni",
"Navigation": "Navigazione",
"Set status for {{count}} book(s)_one": "Imposta stato per {{count}} libro",
"Set status for {{count}} book(s)_other": "Imposta stato per {{count}} libri",
"Mark as Unread": "Segna come non letto",
"Mark as Finished": "Segna come finito",
"Finished": "Finito",
"Unread": "Non letto",
"Clear Status": "Cancella stato",
"Status": "Stato",
"Set status for {{count}} book(s)_many": "Imposta stato per {{count}} libri",
"Loading": "Caricamento...",
"Exit Paragraph Mode": "Esci dalla modalità paragrafo",
"Paragraph Mode": "Modalità paragrafo",
"Embedding Model": "Modello di incorporazione",
"{{count}} book(s) synced_one": "{{count}} libro sincronizzato",
"{{count}} book(s) synced_many": "{{count}} libri sincronizzati",
"{{count}} book(s) synced_other": "{{count}} libri sincronizzati",
"Unable to start RSVP": "Impossibile avviare RSVP",
"RSVP not supported for PDF": "RSVP non supportato per PDF",
"Select Chapter": "Seleziona capitolo",
"Context": "Contesto",
"Ready": "Pronto",
"Chapter Progress": "Progresso capitolo",
"words": "parole",
"{{time}} left": "{{time}} rimanenti",
"Reading progress": "Progresso lettura",
"Skip back 15 words": "Indietro di 15 parole",
"Back 15 words (Shift+Left)": "Indietro di 15 parole (Shift+Sinistra)",
"Pause (Space)": "Pausa (Spazio)",
"Play (Space)": "Riproduci (Spazio)",
"Skip forward 15 words": "Avanti di 15 parole",
"Forward 15 words (Shift+Right)": "Avanti di 15 parole (Shift+Destra)",
"Decrease speed": "Diminuisci velocità",
"Slower (Left/Down)": "Più lento (Sinistra/Giù)",
"Increase speed": "Aumenta velocità",
"Faster (Right/Up)": "Più veloce (Destra/Su)",
"Start RSVP Reading": "Avvia lettura RSVP",
"Choose where to start reading": "Scegli dove iniziare a leggere",
"From Chapter Start": "Dall'inizio del capitolo",
"Start reading from the beginning of the chapter": "Inizia a leggere dall'inizio del capitolo",
"Resume": "Riprendi",
"Continue from where you left off": "Continua da dove avevi interrotto",
"From Current Page": "Dalla pagina corrente",
"Start from where you are currently reading": "Inizia da dove stai leggendo",
"From Selection": "Dalla selezione",
"Speed Reading Mode": "Modalità lettura veloce",
"Scroll left": "Scorri a sinistra",
"Scroll right": "Scorri a destra",
"Library Sync Progress": "Avanzamento sincronizzazione libreria",
"Back to library": "Torna alla libreria",
"Group by...": "Raggruppa per...",
"Export as Plain Text": "Esporta come testo normale",
"Export as Markdown": "Esporta come Markdown",
"Show Page Navigation Buttons": "Tasti navigazione",
"Page {{number}}": "Pagina {{number}}",
"highlight": "evidenziazione",
"underline": "sottolineatura",
"squiggly": "ondulato",
"red": "rosso",
"violet": "viola",
"blue": "blu",
"green": "verde",
"yellow": "giallo",
"Select {{style}} style": "Seleziona lo stile {{style}}",
"Select {{color}} color": "Seleziona il colore {{color}}",
"Close Book": "Chiudi libro",
"Speed Reading": "Lettura veloce",
"Close Speed Reading": "Chiudi lettura veloce",
"Authors": "Autori",
"Books": "Libri",
"Groups": "Gruppi",
"Back to TTS Location": "Torna alla posizione TTS",
"Metadata": "Metadati",
"Image viewer": "Visualizzatore immagini",
"Previous Image": "Immagine precedente",
"Next Image": "Immagine successiva",
"Zoomed": "Zoomato",
"Zoom level": "Livello di zoom",
"Table viewer": "Visualizzatore tabelle",
"Unable to connect to Readwise. Please check your network connection.": "Impossibile connettersi a Readwise. Controlla la tua connessione di rete.",
"Invalid Readwise access token": "Token di accesso Readwise non valido",
"Disconnected from Readwise": "Disconnesso da Readwise",
"Never": "Mai",
"Readwise Settings": "Impostazioni Readwise",
"Connected to Readwise": "Connesso a Readwise",
"Last synced: {{time}}": "Ultima sincronizzazione: {{time}}",
"Sync Enabled": "Sincronizzazione abilitata",
"Disconnect": "Disconnetti",
"Connect your Readwise account to sync highlights.": "Connetti il tuo account Readwise per sincronizzare le evidenziazioni.",
"Get your access token at": "Ottieni il tuo token di accesso su",
"Access Token": "Token di accesso",
"Paste your Readwise access token": "Incolla il tuo token di accesso Readwise",
"Config": "Configurazione",
"Readwise Sync": "Sincronizzazione Readwise",
"Push Highlights": "Invia evidenziazioni",
"Highlights synced to Readwise": "Evidenziazioni sincronizzate su Readwise",
"Readwise sync failed: no internet connection": "Sincronizzazione Readwise fallita: nessuna connessione internet",
"Readwise sync failed: {{error}}": "Sincronizzazione Readwise fallita: {{error}}",
"System Screen Brightness": "Luminosità dello schermo del sistema",
"Page:": "Pagina:",
"Page: {{number}}": "Pagina: {{number}}",
"Annotation page number": "Numero di pagina dell'annotazione",
"Translating...": "Traduzione...",
"Show Battery Percentage": "Mostra percentuale batteria",
"Hide Scrollbar": "Nascondi barra di scorrimento",
"Skip to last reading position": "Vai all'ultima posizione di lettura",
"Show context": "Mostra contesto",
"Hide context": "Nascondi contesto",
"Decrease font size": "Riduci dimensione carattere",
"Increase font size": "Aumenta dimensione carattere",
"Focus": "Messa a fuoco",
"Theme color": "Colore del tema",
"Import failed": "Importazione fallita",
"Available Formatters:": "Formattatori disponibili:",
"Format date": "Formatta data",
"Markdown block quote (> per line)": "Citazione Markdown (> per riga)",
"Newlines to <br>": "A capo in <br>",
"Change case": "Cambia maiuscole/minuscole",
"Trim whitespace": "Rimuovi spazi",
"Truncate to n characters": "Tronca a n caratteri",
"Replace text": "Sostituisci testo",
"Fallback value": "Valore predefinito",
"Get length": "Ottieni lunghezza",
"First/last element": "Primo/ultimo elemento",
"Join array": "Unisci array",
"Backup failed: {{error}}": "Backup fallito: {{error}}",
"Select Backup": "Seleziona backup",
"Restore failed: {{error}}": "Ripristino fallito: {{error}}",
"Backup & Restore": "Backup e ripristino",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "Crea un backup della tua libreria o ripristina da un backup precedente. Il ripristino verrà unito alla tua libreria attuale.",
"Backup Library": "Backup libreria",
"Restore Library": "Ripristina libreria",
"Creating backup...": "Creazione backup...",
"Restoring library...": "Ripristino libreria...",
"{{current}} of {{total}} items": "{{current}} di {{total}} elementi",
"Backup completed successfully!": "Backup completato con successo!",
"Restore completed successfully!": "Ripristino completato con successo!",
"Your library has been saved to the selected location.": "La tua libreria è stata salvata nella posizione selezionata.",
"{{added}} books added, {{updated}} books updated.": "{{added}} libri aggiunti, {{updated}} libri aggiornati.",
"Operation failed": "Operazione fallita",
"Loading library...": "Caricamento libreria...",
"{{count}} books refreshed_one": "{{count}} libro aggiornato",
"{{count}} books refreshed_many": "{{count}} libri aggiornati",
"{{count}} books refreshed_other": "{{count}} libri aggiornati",
"Failed to refresh metadata": "Aggiornamento metadati fallito",
"Refresh Metadata": "Aggiorna metadati",
"Keyboard Shortcuts": "Scorciatoie da tastiera",
"View all keyboard shortcuts": "Visualizza tutte le scorciatoie",
"Switch Sidebar Tab": "Cambia scheda barra laterale",
"Toggle Notebook": "Mostra/nascondi blocco note",
"Search in Book": "Cerca nel libro",
"Toggle Scroll Mode": "Attiva/disattiva scorrimento",
"Toggle Select Mode": "Attiva/disattiva selezione",
"Toggle Bookmark": "Attiva/disattiva segnalibro",
"Toggle Text to Speech": "Attiva/disattiva sintesi vocale",
"Play / Pause TTS": "Riproduci / Pausa TTS",
"Toggle Paragraph Mode": "Attiva/disattiva modo paragrafo",
"Highlight Selection": "Evidenzia selezione",
"Underline Selection": "Sottolinea selezione",
"Annotate Selection": "Annota selezione",
"Search Selection": "Cerca selezione",
"Copy Selection": "Copia selezione",
"Translate Selection": "Traduci selezione",
"Dictionary Lookup": "Cerca nel dizionario",
"Wikipedia Lookup": "Cerca su Wikipedia",
"Read Aloud Selection": "Leggi la selezione ad alta voce",
"Proofread Selection": "Correggi selezione",
"Open Settings": "Apri impostazioni",
"Open Command Palette": "Apri tavolozza comandi",
"Show Keyboard Shortcuts": "Mostra scorciatoie da tastiera",
"Open Books": "Apri libri",
"Toggle Fullscreen": "Attiva/disattiva schermo intero",
"Close Window": "Chiudi finestra",
"Quit App": "Esci dall'app",
"Go Left / Previous Page": "Vai a sinistra / Pagina precedente",
"Go Right / Next Page": "Vai a destra / Pagina successiva",
"Go Up": "Vai su",
"Go Down": "Vai giù",
"Previous Chapter": "Capitolo precedente",
"Next Chapter": "Capitolo successivo",
"Scroll Half Page Down": "Scorri mezza pagina in basso",
"Scroll Half Page Up": "Scorri mezza pagina in alto",
"Save Note": "Salva nota",
"Single Section Scroll": "Scorrimento a sezione singola",
"General": "Generale",
"Text to Speech": "Sintesi vocale",
"Zoom": "Zoom",
"Window": "Finestra",
"Your Bookshelf": "La tua libreria",
"TTS": "Sintesi vocale",
"Media Info": "Info multimediali",
"Update Frequency": "Frequenza aggiornamento",
"Every Sentence": "Ogni frase",
"Every Paragraph": "Ogni paragrafo",
"Every Chapter": "Ogni capitolo",
"TTS Media Info Update Frequency": "Frequenza aggiornamento info multimediali TTS",
"Select reading speed": "Seleziona velocità di lettura",
"Drag to seek": "Trascina per cercare",
"Punctuation Delay": "Ritardo punteggiatura",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "Conferma che questa connessione OPDS verrà instradata attraverso i server Readest nell'app web prima di continuare.",
"Custom Headers": "Intestazioni personalizzate",
"Custom Headers (optional)": "Intestazioni personalizzate (facoltativo)",
"Add one header per line using \"Header-Name: value\".": "Aggiungi un'intestazione per riga usando \"Header-Name: value\".",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "Capisco che questa connessione OPDS verrà instradata attraverso i server Readest nell'app web. Se non mi fido di Readest con queste credenziali o intestazioni, dovrei usare l'app nativa.",
"Unable to connect to Hardcover. Please check your network connection.": "Impossibile connettersi a Hardcover. Controlla la connessione di rete.",
"Invalid Hardcover API token": "Token API Hardcover non valido",
"Disconnected from Hardcover": "Disconnesso da Hardcover",
"Hardcover Settings": "Impostazioni Hardcover",
"Connected to Hardcover": "Connesso a Hardcover",
"Connect your Hardcover account to sync reading progress and notes.": "Collega il tuo account Hardcover per sincronizzare i progressi di lettura e le note.",
"Get your API token from hardcover.app → Settings → API.": "Ottieni il tuo token API da hardcover.app → Impostazioni → API.",
"API Token": "Token API",
"Paste your Hardcover API token": "Incolla il tuo token API Hardcover",
"Hardcover sync enabled for this book": "Sincronizzazione Hardcover attivata per questo libro",
"Hardcover sync disabled for this book": "Sincronizzazione Hardcover disattivata per questo libro",
"Hardcover Sync": "Sincronizzazione Hardcover",
"Enable for This Book": "Attiva per questo libro",
"Push Notes": "Invia note",
"Enable Hardcover sync for this book first.": "Attiva prima la sincronizzazione Hardcover per questo libro.",
"No annotations or excerpts to sync for this book.": "Nessuna annotazione o estratto da sincronizzare per questo libro.",
"Configure Hardcover in Settings first.": "Configura prima Hardcover nelle impostazioni.",
"No new Hardcover note changes to sync.": "Nessuna nuova modifica alle note Hardcover da sincronizzare.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover sincronizzato: {{inserted}} nuovi, {{updated}} aggiornati, {{skipped}} invariati",
"Hardcover notes sync failed: {{error}}": "Sincronizzazione note Hardcover non riuscita: {{error}}",
"Reading progress synced to Hardcover": "Progressi di lettura sincronizzati con Hardcover",
"Hardcover progress sync failed: {{error}}": "Sincronizzazione progressi Hardcover non riuscita: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "Mantieni l'identificatore sorgente esistente",
"Toggle Toolbar": "Mostra/nascondi barra degli strumenti"
}
@@ -8,7 +8,6 @@
"Auto Mode": "自動モード",
"Behavior": "動作",
"Book": "書籍",
"Book Cover": "表紙",
"Bookmark": "ブックマーク",
"Cancel": "キャンセル",
"Chapter": "章",
@@ -46,7 +45,6 @@
"Horizontal Direction": "横書",
"Hyphenation": "ハイフネーション",
"Import Books": "書籍をインポート",
"Language:": "言語:",
"Layout": "レイアウト",
"Light Mode": "ライトモード",
"Loading...": "読み込み中...",
@@ -68,8 +66,8 @@
"Paging Animation": "ページめくりアニメーション",
"Paragraph": "段落",
"Parallel Read": "並列読書",
"Published:": "出版日",
"Publisher:": "出版社",
"Published": "出版日",
"Publisher": "出版社",
"Reading Progress Synced": "読書進捗が同期されました",
"Reload Page": "ページを再読み込み",
"Reveal in File Explorer": "エクスプローラーで表示",
@@ -83,7 +81,6 @@
"Search...": "検索...",
"Select Book": "書籍を選択",
"Select Books": "書籍を選択",
"Select Multiple Books": "複数の書籍を選択",
"Sepia": "セピア",
"Serif Font": "セリフ体",
"Show Book Details": "書籍の詳細を表示",
@@ -94,23 +91,21 @@
"Slow": "低速",
"Solarized": "ソーラライズド",
"Speak": "読み上げ",
"Subjects:": "主題",
"Subjects": "主題",
"System Fonts": "システムフォント",
"TTS not supported in this device": "このデバイスではTTSがサポートされていません",
"Theme Color": "テーマカラー",
"Theme Mode": "テーマモード",
"Translate": "翻訳",
"Translated Text": "翻訳されたテキスト",
"Unknown": "不明",
"Untitled": "無題",
"Updated:": "更新日",
"Updated": "更新日",
"Version {{version}}": "バージョン {{version}}",
"Vertical Direction": "縦書",
"Welcome to your library. You can import your books here and read them anytime.": "ライブラリーへようこそ。ここに書籍をインポートして、いつでも読むことができます。",
"Wikipedia": "ウィキペディア",
"Writing Mode": "書き込みモード",
"Your Library": "ライブラリー",
"TTS not supported for PDF": "PDFではTTSがサポートされていません",
"Override Book Font": "書籍フォントを上書き",
"Apply to All Books": "すべての書籍に適用",
"Apply to This Book": "この書籍に適用",
@@ -120,6 +115,7 @@
"Book Details": "書籍の詳細",
"From Local File": "ローカルファイルから",
"TOC": "目次",
"Table of Contents": "目次",
"Book uploaded: {{title}}": "書籍がアップロードされました:{{title}}",
"Failed to upload book: {{title}}": "書籍のアップロードに失敗しました:{{title}}",
"Book downloaded: {{title}}": "書籍がダウンロードされました:{{title}}",
@@ -176,9 +172,6 @@
"Token": "トークン",
"Your OTP token": "あなたのOTPトークン",
"Verify token": "トークンを確認",
"Sign in with Google": "Googleでサインイン",
"Sign in with Apple": "Appleでサインイン",
"Sign in with GitHub": "GitHubでサインイン",
"Account": "アカウント",
"Failed to delete user. Please try again later.": "ユーザーの削除に失敗しました。後ほど再試行してください。",
"Community Support": "コミュニティサポート",
@@ -191,12 +184,11 @@
"RTL Direction": "RTL方向",
"Maximum Column Height": "最大列高",
"Maximum Column Width": "最大列幅",
"Continuous Scroll": "連続スクロール",
"Fullscreen": "全画面",
"No supported files found. Supported formats: {{formats}}": "サポートされているファイルが見つかりません。サポートされている形式:{{formats}}",
"Drop to Import Books": "書籍をインポートするにはドロップ",
"Custom": "カスタム",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "全世界は舞台であり、\nそしてすべての男性と女性は単なる役者です。\n彼らは出入り口を持っており、\nそして一人の男性は時に多くの役を演じます。\n彼の行為は七つの時代です。\n\n— ウィリアム・シェイクスピア",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "全世界は舞台であり、\nそしてすべての男性と女性は単なる役者です。\n彼らは出入り口を持っており、\nそして一人の男性は時に多くの役を演じます。\n彼の行為は七つの時代です。\n\n— ウィリアム・シェイクスピア",
"Custom Theme": "カスタムテーマ",
"Theme Name": "テーマ名",
"Text Color": "テキストカラー",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "ファイルを開くと自動インポート",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "章が検出されません",
"Failed to parse the EPUB file.": "EPUBファイルの解析に失敗しました",
"This book format is not supported.": "この書籍形式はサポートされていません",
"No chapters detected": "章が検出されません",
"Failed to parse the EPUB file": "EPUBファイルの解析に失敗しました",
"This book format is not supported": "この書籍形式はサポートされていません",
"Unable to fetch the translation. Please log in first and try again.": "翻訳を取得できません。まずログインして再試行してください。",
"Group": "グループ",
"Always on Top": "常に最前面",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "ダウンロード中 {{downloaded}} / {{contentLength}}",
"Download finished": "ダウンロード完了",
"DOWNLOAD & INSTALL": "更新",
"Changelog:": "変更ログ",
"Changelog": "変更ログ",
"Software Update": "ソフトウェアの更新",
"Title": "タイトル",
"Date Read": "読書日",
@@ -253,18 +245,15 @@
"Ascending": "昇順",
"Descending": "降順",
"Sort by...": "並べ替え...",
"Added:": "追加日",
"Format:": "形式:",
"Added": "追加日",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "説明",
"Description": "説明",
"No description available": "説明はありません",
"List": "リスト",
"Grid": "グリッド",
"(from 'As You Like It', Act II)": "(「お気に召すまま」第2幕)",
"Link Color": "リンクカラー",
"Volume Keys for Page Flip": "音量キーでページめくり",
"Clicks for Page Flip": "タップでページめくり",
"Swap Clicks Area": "タップ領域を入れ替え",
"Screen": "画面",
"Orientation": "向き",
"Portrait": "縦",
@@ -273,7 +262,7 @@
"Checking for updates...": "更新を確認中...",
"Error checking for updates": "更新の確認中にエラーが発生しました",
"Details": "詳細",
"File Size:": "ファイルサイズ",
"File Size": "ファイルサイズ",
"Auto Detect": "自動検出",
"Next Section": "次のセクション",
"Previous Section": "前のセクション",
@@ -299,7 +288,6 @@
"Disable Translation": "翻訳を無効にする",
"Scroll": "スクロール",
"Overlap Pixels": "重なりピクセル",
"Click": "クリック",
"System Language": "システム言語",
"Security": "セキュリティ",
"Allow JavaScript": "JavaScriptを許可",
@@ -312,7 +300,6 @@
"Synced at {{time}}": "{{time}} に同期済み",
"Never synced": "まだ同期されていません",
"Show Remaining Time": "残り時間を表示",
"Show Page Number": "ページ番号を表示",
"{{time}} min left in chapter": "{{time}}分残り",
"Override Book Color": "書籍の色を上書き",
"Login Required": "ログイン必須",
@@ -334,7 +321,6 @@
"Left Margin (px)": "左マージン (px)",
"Column Gap (%)": "列間の間隔 (%)",
"Always Show Status Bar": "ステータスバーを常に表示",
"Translation Not Available": "翻訳は利用できません",
"Custom Content CSS": "コンテンツCSS",
"Enter CSS for book content styling...": "本のコンテンツ用CSSを入力...",
"Custom Reader UI CSS": "リーダーUIのCSS",
@@ -344,10 +330,10 @@
"Fit": "フィット",
"Reset {{settings}}": "{{settings}}をリセット",
"Reset Settings": "設定をリセット",
"{{count}} pages left in chapter_other": "{{count}} ページ残り",
"{{count}} pages left in chapter_other": "<0>{{count}}</0><1> ページ残り</1>",
"Show Remaining Pages": "残りを表示",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "サブスクリプションを管理",
"Coming Soon": "近日公開",
@@ -355,7 +341,6 @@
"Upgrade to Plus or Pro": "Plus または Pro にアップグレード",
"Current Plan": "現在のプラン",
"Plan Limits": "プランの上限",
"Failed to manage subscription. Please try again later.": "サブスクリプションの管理に失敗しました。後でもう一度お試しください。",
"Processing your payment...": "お支払いを処理中...",
"Please wait while we confirm your subscription.": "サブスクリプションを確認しています。しばらくお待ちください。",
"Payment Processing": "支払いを処理中",
@@ -368,7 +353,6 @@
"Email:": "メール:",
"Plan:": "プラン:",
"Amount:": "金額:",
"Subscription ID:": "サブスクリプションID:",
"Go to Library": "ライブラリへ移動",
"Need help? Contact our support team at support@readest.com": "サポートが必要ですか? support@readest.com までお問い合わせください。",
"Free Plan": "無料プラン",
@@ -398,7 +382,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "制限なくテキストを音声化。",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "高度な翻訳機能を利用可能に。",
"DeepL Pro Access": "DeepL Pro利用",
"2 GB Cloud Sync Storage": "2GBクラウド保存",
"Enjoy faster responses and dedicated assistance whenever you need help.": "優先サポートを利用可能。",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "翻訳上限に達しました。アップグレードで継続可能です。",
"Includes All Plus Plan Benefits": "Plusプランの全特典を含む",
@@ -408,10 +391,784 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "スマートな読書、翻訳、コンテンツ発見のための強力なAIツールを活用。",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "最も正確な翻訳エンジンで1日最大10万文字を翻訳。",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "最も正確な翻訳エンジンで1日最大50万文字を翻訳。",
"10 GB Cloud Sync Storage": "10GBクラウド同期ストレージ",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "最大2GBの安全なクラウドストレージで読書コレクション全体を保存・アクセス。",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "最大10GBの安全なクラウドストレージで読書コレクション全体を保存・アクセス。",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "最大5GBの安全なクラウドストレージで読書コレクション全体を保存・アクセス。",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "最大20GBの安全なクラウドストレージで読書コレクション全体を保存・アクセス。",
"Deleted cloud backup of the book: {{title}}": "書籍のクラウドバックアップを削除しました:{{title}}",
"Failed to delete cloud backup of the book": "書籍のクラウドバックアップを削除できませんでした",
"Are you sure to delete the cloud backup of the selected book?": "選択した書籍のクラウドバックアップを削除してもよろしいですか?"
"Are you sure to delete the cloud backup of the selected book?": "選択した書籍のクラウドバックアップを削除してもよろしいですか?",
"What's New in Readest": "Readestの新機能",
"Enter book title": "本のタイトルを入力",
"Subtitle": "サブタイトル",
"Enter book subtitle": "本のサブタイトルを入力",
"Enter author name": "著者名を入力",
"Series": "シリーズ",
"Enter series name": "シリーズ名を入力",
"Series Index": "シリーズ番号",
"Enter series index": "シリーズ番号を入力",
"Total in Series": "シリーズ総数",
"Enter total books in series": "シリーズの総冊数を入力",
"Enter publisher": "出版社を入力",
"Publication Date": "出版日",
"Identifier": "識別子",
"Enter book description": "本の説明を入力",
"Change cover image": "表紙画像を変更",
"Replace": "置き換え",
"Unlock cover": "表紙のロックを解除",
"Lock cover": "表紙をロック",
"Auto-Retrieve Metadata": "メタデータを自動取得",
"Auto-Retrieve": "自動取得",
"Unlock all fields": "すべてのフィールドのロックを解除",
"Unlock All": "すべてロック解除",
"Lock all fields": "すべてのフィールドをロック",
"Lock All": "すべてロック",
"Reset": "リセット",
"Edit Metadata": "メタデータを編集",
"Locked": "ロック中",
"Select Metadata Source": "メタデータソースを選択",
"Keep manual input": "手動入力を保持",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "小説、科学、歴史",
"Open Book in New Window": "新しいウィンドウで本を開く",
"Voices for {{lang}}": "{{lang}}の音声",
"Yandex Translate": "Yandex翻訳",
"YYYY or YYYY-MM-DD": "YYYYまたはYYYY-MM-DD",
"Restore Purchase": "購入を復元",
"No purchases found to restore.": "復元する購入が見つかりません。",
"Failed to restore purchases.": "購入の復元に失敗しました。",
"Failed to manage subscription.": "サブスクリプションの管理に失敗しました。",
"Failed to load subscription plans.": "サブスクリプションプランの読み込みに失敗しました。",
"year": "年",
"Failed to create checkout session": "チェックアウトセッションの作成に失敗しました",
"Storage": "ストレージ",
"Terms of Service": "利用規約",
"Privacy Policy": "プライバシーポリシー",
"Disable Double Click": "ダブルクリック無効",
"TTS not supported for this document": "TTSはこのドキュメントではサポートされていません",
"Reset Password": "パスワードをリセット",
"Show Reading Progress": "読書進捗を表示",
"Reading Progress Style": "読書進捗スタイル",
"Page Number": "ページ番号",
"Percentage": "パーセンテージ",
"Deleted local copy of the book: {{title}}": "書籍のローカルコピーを削除しました:{{title}}",
"Failed to delete cloud backup of the book: {{title}}": "書籍のクラウドバックアップの削除に失敗しました:{{title}}",
"Failed to delete local copy of the book: {{title}}": "書籍のローカルコピーの削除に失敗しました:{{title}}",
"Are you sure to delete the local copy of the selected book?": "選択した書籍のローカルコピーを削除してもよろしいですか?",
"Remove from Cloud & Device": "クラウドとデバイスから削除",
"Remove from Cloud Only": "クラウドからのみ削除",
"Remove from Device Only": "デバイスからのみ削除",
"Disconnected": "切断されました",
"KOReader Sync Settings": "KOReader Sync設定",
"Sync Strategy": "同期戦略",
"Ask on conflict": "競合時に確認",
"Always use latest": "最新を常に使用",
"Send changes only": "変更のみを送信",
"Receive changes only": "変更のみを受信",
"Checksum Method": "チェックサム方式",
"File Content (recommended)": "ファイル内容(推奨)",
"File Name": "ファイル名",
"Device Name": "デバイス名",
"Connect to your KOReader Sync server.": "KOReader Syncサーバーに接続します。",
"Server URL": "サーバーURL",
"Username": "ユーザー名",
"Your Username": "あなたのユーザー名",
"Password": "パスワード",
"Connect": "接続",
"KOReader Sync": "KOReader Sync",
"Sync Conflict": "同期競合",
"Sync reading progress from \"{{deviceName}}\"?": "{{deviceName}}から読書進捗を同期しますか?",
"another device": "別のデバイス",
"Local Progress": "ローカル進捗",
"Remote Progress": "リモート進捗",
"Page {{page}} of {{total}} ({{percentage}}%)": "ページ {{page}} / {{total}} ({{percentage}}%)",
"Current position": "現在の位置",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "おおよそページ {{page}} / {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "おおよそ {{percentage}}%",
"Failed to connect": "接続に失敗しました",
"Sync Server Connected": "同期サーバーに接続されました",
"Sync as {{userDisplayName}}": "{{userDisplayName}} として同期",
"Custom Fonts": "カスタムフォント",
"Cancel Delete": "削除をキャンセル",
"Import Font": "フォントをインポート",
"Delete Font": "フォントを削除",
"Tips": "ヒント",
"Custom fonts can be selected from the Font Face menu": "カスタムフォントは書体メニューから選択できます",
"Manage Custom Fonts": "カスタムフォント管理",
"Select Files": "ファイルを選択",
"Select Image": "画像を選択",
"Select Video": "動画を選択",
"Select Audio": "音声を選択",
"Select Fonts": "フォントを選択",
"Supported font formats: .ttf, .otf, .woff, .woff2": "サポートされているフォント形式:.ttf, .otf, .woff, .woff2",
"Push Progress": "進捗をプッシュ",
"Pull Progress": "進捗をプル",
"Previous Paragraph": "前の段落",
"Previous Sentence": "前の文",
"Pause": "一時停止",
"Play": "再生",
"Next Sentence": "次の文",
"Next Paragraph": "次の段落",
"Separate Cover Page": "別の表紙ページ",
"Resize Notebook": "ノートのサイズ変更",
"Resize Sidebar": "サイドバーのサイズ変更",
"Get Help from the Readest Community": "Readestコミュニティからヘルプを得る",
"Remove cover image": "表紙画像を削除",
"Bookshelf": "本棚",
"View Menu": "メニューを表示",
"Settings Menu": "設定メニュー",
"View account details and quota": "アカウントの詳細とクォータを表示",
"Library Header": "ライブラリヘッダー",
"Book Content": "本の内容",
"Footer Bar": "フッターバー",
"Header Bar": "ヘッダーバー",
"View Options": "表示オプション",
"Book Menu": "本のメニュー",
"Search Options": "検索オプション",
"Close": "閉じる",
"Delete Book Options": "本の削除オプション",
"ON": "オン",
"OFF": "オフ",
"Reading Progress": "読書進捗",
"Page Margin": "ページマージン",
"Remove Bookmark": "ブックマークを削除",
"Add Bookmark": "ブックマークを追加",
"Books Content": "本の内容",
"Jump to Location": "位置にジャンプ",
"Unpin Notebook": "ノートブックのピン留めを解除",
"Pin Notebook": "ノートブックをピン留め",
"Hide Search Bar": "検索バーを隠す",
"Show Search Bar": "検索バーを表示",
"On {{current}} of {{total}} page": "ページ {{current}} / {{total}}",
"Section Title": "セクションタイトル",
"Decrease": "減少",
"Increase": "増加",
"Settings Panels": "設定パネル",
"Settings": "設定",
"Unpin Sidebar": "サイドバーのピン留めを解除",
"Pin Sidebar": "サイドバーをピン留め",
"Toggle Sidebar": "サイドバーの切り替え",
"Toggle Translation": "翻訳の切り替え",
"Translation Disabled": "翻訳が無効化されました",
"Minimize": "最小化",
"Maximize or Restore": "最大化または復元",
"Exit Parallel Read": "並行読書を終了",
"Enter Parallel Read": "並行読書に入る",
"Zoom Level": "ズームレベル",
"Zoom Out": "ズームアウト",
"Reset Zoom": "ズームリセット",
"Zoom In": "ズームイン",
"Zoom Mode": "ズームモード",
"Single Page": "シングルページ",
"Auto Spread": "自動スプレッド",
"Fit Page": "ページに合わせる",
"Fit Width": "幅に合わせる",
"Failed to select directory": "ディレクトリの選択に失敗しました",
"The new data directory must be different from the current one.": "新しいデータディレクトリは現在のものと異なる必要があります。",
"Migration failed: {{error}}": "移行に失敗しました: {{error}}",
"Change Data Location": "データの場所を変更",
"Current Data Location": "現在のデータの場所",
"Total size: {{size}}": "合計サイズ: {{size}}",
"Calculating file info...": "ファイル情報を計算中...",
"New Data Location": "新しいデータの場所",
"Choose Different Folder": "別のフォルダーを選択",
"Choose New Folder": "新しいフォルダーを選択",
"Migrating data...": "データを移行中...",
"Copying: {{file}}": "コピー中: {{file}}",
"{{current}} of {{total}} files": "{{current}} / {{total}} ファイル",
"Migration completed successfully!": "移行が成功しました!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "データは新しい場所に移動されました。プロセスを完了するにはアプリケーションを再起動してください。",
"Migration failed": "移行に失敗しました",
"Important Notice": "重要なお知らせ",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "これにより、すべてのアプリデータが新しい場所に移動されます。宛先に十分な空き容量があることを確認してください。",
"Restart App": "アプリを再起動",
"Start Migration": "移行を開始",
"Advanced Settings": "詳細設定",
"File count: {{size}}": "ファイル数: {{size}}",
"Background Read Aloud": "バックグラウンド読み上げ",
"Ready to read aloud": "読み上げの準備ができました",
"Read Aloud": "読み上げ",
"Screen Brightness": "画面の明るさ",
"Background Image": "背景画像",
"Import Image": "画像をインポート",
"Opacity": "不透明度",
"Size": "サイズ",
"Cover": "カバー",
"Contain": "含む",
"{{number}} pages left in chapter": "<1>章に</1><0>{{number}}</0><1>ページ残り</1>",
"Device": "デバイス",
"E-Ink Mode": "E-Inkモード",
"Highlight Colors": "ハイライトカラー",
"Pagination": "ページネーション",
"Disable Double Tap": "ダブルタップを無効にする",
"Tap to Paginate": "タップしてページを切り替える",
"Click to Paginate": "クリックしてページを切り替える",
"Tap Both Sides": "両側をタップ",
"Click Both Sides": "両側をクリック",
"Swap Tap Sides": "タップサイドを入れ替える",
"Swap Click Sides": "クリックサイドを入れ替える",
"Source and Translated": "原文と翻訳",
"Translated Only": "翻訳のみ",
"Source Only": "原文のみ",
"TTS Text": "TTSテキスト",
"The book file is corrupted": "本のファイルが破損しています",
"The book file is empty": "本のファイルが空です",
"Failed to open the book file": "本のファイルを開くことができませんでした",
"On-Demand Purchase": "オンデマンド購入",
"Full Customization": "フルカスタマイズ",
"Lifetime Plan": "ライフタイムプラン",
"One-Time Payment": "ワンタイムペイメント",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "すべてのデバイスで特定の機能にライフタイムアクセスを楽しむために、1回の支払いを行います。必要なときにのみ特定の機能やサービスを購入します。",
"Expand Cloud Sync Storage": "クラウド同期ストレージを拡張",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "1回の購入でクラウドストレージを永遠に拡張します。追加の購入ごとに、さらに多くのスペースが追加されます。",
"Unlock All Customization Options": "すべてのカスタマイズオプションを解除",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "追加のテーマ、フォント、レイアウトオプション、読み上げ、翻訳者、クラウドストレージサービスを解除します。",
"Purchase Successful!": "購入成功!",
"lifetime": "ライフタイム",
"Thank you for your purchase! Your payment has been processed successfully.": "ご購入ありがとうございます!お支払いが正常に処理されました。",
"Order ID:": "購入ID",
"TTS Highlighting": "TTSハイライト",
"Style": "スタイル",
"Underline": "下線",
"Strikethrough": "取り消し線",
"Squiggly": "波線",
"Outline": "アウトライン",
"Save Current Color": "現在の色を保存",
"Quick Colors": "クイックカラー",
"Highlighter": "蛍光ペン",
"Save Book Cover": "本のカバーを保存",
"Auto-save last book cover": "最後の本のカバーを自動保存",
"Back": "戻る",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "確認メールを送信しました。変更を確認するために、古いメールアドレスと新しいメールアドレスを確認してください。",
"Failed to update email": "メールの更新に失敗しました",
"New Email": "新しいメールアドレス",
"Your new email": "あなたの新しいメールアドレス",
"Updating email ...": "メールを更新しています ...",
"Update email": "メールを更新",
"Current email": "現在のメールアドレス",
"Update Email": "メールを更新",
"All": "すべて",
"Unable to open book": "本を開くことができません",
"Punctuation": "句読点",
"Replace Quotation Marks": "引用符を置き換える",
"Enabled only in vertical layout.": "縦書きレイアウトでのみ有効です。",
"No Conversion": "変換なし",
"Simplified to Traditional": "簡体字 → 繁体字",
"Traditional to Simplified": "繁体字 → 簡体字",
"Simplified to Traditional (Taiwan)": "簡体字 → 繁体字(台湾)",
"Simplified to Traditional (Hong Kong)": "簡体字 → 繁体字(香港)",
"Simplified to Traditional (Taiwan), with phrases": "簡体字 → 繁体字(台湾)• フレーズ",
"Traditional (Taiwan) to Simplified": "繁体字(台湾) → 簡体字",
"Traditional (Hong Kong) to Simplified": "繁体字(香港) → 簡体字",
"Traditional (Taiwan) to Simplified, with phrases": "繁体字(台湾) → 簡体字 • フレーズ",
"Convert Simplified and Traditional Chinese": "簡体字/繁体字変換",
"Convert Mode": "変換モード",
"Failed to auto-save book cover for lock screen: {{error}}": "ロック画面の本のカバーの自動保存に失敗しました:{{error}}",
"Download from Cloud": "クラウドからダウンロード",
"Upload to Cloud": "クラウドにアップロード",
"Clear Custom Fonts": "カスタムフォントをクリア",
"Columns": "列",
"OPDS Catalogs": "OPDSカタログ",
"Adding LAN addresses is not supported in the web app version.": "Webアプリ版ではLANアドレスの追加はサポートされていません。",
"Invalid OPDS catalog. Please check the URL.": "無効なOPDSカタログです。URLを確認してください。",
"Browse and download books from online catalogs": "オンラインカタログから本を閲覧・ダウンロード",
"My Catalogs": "マイカタログ",
"Add Catalog": "カタログを追加",
"No catalogs yet": "まだカタログはありません",
"Add your first OPDS catalog to start browsing books": "本を閲覧するには、最初のOPDSカタログを追加してください。",
"Add Your First Catalog": "最初のカタログを追加",
"Browse": "閲覧",
"Popular Catalogs": "人気カタログ",
"Add": "追加",
"Add OPDS Catalog": "OPDSカタログを追加",
"Catalog Name": "カタログ名",
"My Calibre Library": "私のCalibreライブラリ",
"OPDS URL": "OPDS URL",
"Username (optional)": "ユーザー名(任意)",
"Password (optional)": "パスワード(任意)",
"Description (optional)": "説明(任意)",
"A brief description of this catalog": "このカタログの簡単な説明",
"Validating...": "検証中...",
"View All": "すべて表示",
"Forward": "進む",
"Home": "ホーム",
"{{count}} items_other": "{{count}} 件",
"Download completed": "ダウンロード完了",
"Download failed": "ダウンロード失敗",
"Open Access": "オープンアクセス",
"Borrow": "借りる",
"Buy": "購入",
"Subscribe": "購読",
"Sample": "サンプル",
"Download": "ダウンロード",
"Open & Read": "開いて読む",
"Tags": "タグ",
"Tag": "タグ",
"First": "最初",
"Previous": "前へ",
"Next": "次へ",
"Last": "最後",
"Cannot Load Page": "ページを読み込めません",
"An error occurred": "エラーが発生しました",
"Online Library": "オンラインライブラリ",
"URL must start with http:// or https://": "URLはhttp://またはhttps://で始まる必要があります",
"Title, Author, Tag, etc...": "タイトル、著者、タグなど...",
"Query": "クエリ",
"Subject": "件名",
"Enter {{terms}}": "{{terms}}を入力してください",
"No search results found": "検索結果が見つかりません",
"Failed to load OPDS feed: {{status}} {{statusText}}": "OPDSフィードの読み込みに失敗しました: {{status}} {{statusText}}",
"Search in {{title}}": "{{title}}内を検索",
"Manage Storage": "ストレージ管理",
"Failed to load files": "ファイルの読み込みに失敗しました",
"Deleted {{count}} file(s)_other": "{{count}} 件のファイルを削除しました",
"Failed to delete {{count}} file(s)_other": "{{count}} 件のファイルの削除に失敗しました",
"Failed to delete files": "ファイルの削除に失敗しました",
"Total Files": "ファイル合計",
"Total Size": "合計サイズ",
"Quota": "容量制限",
"Used": "使用済み",
"Files": "ファイル",
"Search files...": "ファイルを検索...",
"Newest First": "新しい順",
"Oldest First": "古い順",
"Largest First": "大きい順",
"Smallest First": "小さい順",
"Name A-Z": "名前 A-Z",
"Name Z-A": "名前 Z-A",
"{{count}} selected_other": "{{count}} 件選択済み",
"Delete Selected": "選択した項目を削除",
"Created": "作成日",
"No files found": "ファイルが見つかりません",
"No files uploaded yet": "まだファイルがアップロードされていません",
"files": "ファイル",
"Page {{current}} of {{total}}": "ページ {{current}} / {{total}}",
"Are you sure to delete {{count}} selected file(s)?_other": "選択した {{count}} 件のファイルを削除してもよろしいですか?",
"Cloud Storage Usage": "クラウドストレージ使用量",
"Rename Group": "グループ名を変更",
"From Directory": "ディレクトリから",
"Successfully imported {{count}} book(s)_other": "成功裏に{{count}}冊の本をインポートしました",
"Count": "件数",
"Start Page": "開始ページ",
"Search in OPDS Catalog...": "OPDSカタログ内を検索...",
"Please log in to use advanced TTS features": "高度なTTS機能を使用するにはログインしてください",
"Word limit of 30 words exceeded.": "30語の上限を超えています。",
"Proofread": "校正",
"Current selection": "現在の選択",
"All occurrences in this book": "この本内のすべての出現箇所",
"All occurrences in your library": "ライブラリ内のすべての出現箇所",
"Selected text:": "選択されたテキスト:",
"Replace with:": "置換後:",
"Enter text...": "テキストを入力…",
"Case sensitive:": "大文字と小文字を区別:",
"Scope:": "適用範囲:",
"Selection": "選択",
"Library": "ライブラリ",
"Yes": "はい",
"No": "いいえ",
"Proofread Replacement Rules": "校正置換ルール",
"Selected Text Rules": "選択テキストのルール",
"No selected text replacement rules": "選択されたテキストの置換ルールはありません",
"Book Specific Rules": "書籍別ルール",
"No book-level replacement rules": "書籍レベルの置換ルールはありません",
"Disable Quick Action": "クイックアクションを無効にする",
"Enable Quick Action on Selection": "選択時にクイックアクションを有効にする",
"None": "なし",
"Annotation Tools": "注釈ツール",
"Enable Quick Actions": "クイックアクションを有効にする",
"Quick Action": "クイックアクション",
"Copy to Notebook": "ノートにコピー",
"Copy text after selection": "選択後のテキストをコピー",
"Highlight text after selection": "選択後のテキストをハイライト",
"Annotate text after selection": "選択後のテキストに注釈を付ける",
"Search text after selection": "選択後のテキストを検索",
"Look up text in dictionary after selection": "選択後のテキストを辞書で調べる",
"Look up text in Wikipedia after selection": "選択後のテキストをWikipediaで調べる",
"Translate text after selection": "選択後のテキストを翻訳する",
"Read text aloud after selection": "選択後のテキストを音読する",
"Proofread text after selection": "選択後のテキストを校正する",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} 進行中、{{pendingCount}} 待機中",
"{{failedCount}} failed": "{{failedCount}} 失敗",
"Waiting...": "待機中...",
"Failed": "失敗",
"Completed": "完了",
"Cancelled": "キャンセル",
"Retry": "再試行",
"Active": "進行中",
"Transfer Queue": "転送キュー",
"Upload All": "すべてアップロード",
"Download All": "すべてダウンロード",
"Resume Transfers": "転送を再開",
"Pause Transfers": "転送を一時停止",
"Pending": "待機中",
"No transfers": "転送なし",
"Retry All": "すべて再試行",
"Clear Completed": "完了を消去",
"Clear Failed": "失敗を消去",
"Upload queued: {{title}}": "アップロードをキューに追加: {{title}}",
"Download queued: {{title}}": "ダウンロードをキューに追加: {{title}}",
"Book not found in library": "ライブラリに本が見つかりません",
"Unknown error": "不明なエラー",
"Please log in to continue": "続行するにはログインしてください",
"Cloud File Transfers": "クラウドファイル転送",
"Show Search Results": "検索結果を表示",
"Search results for '{{term}}'": "「{{term}}」を含む結果",
"Close Search": "検索を閉じる",
"Previous Result": "前の結果",
"Next Result": "次の結果",
"Bookmarks": "ブックマーク",
"Annotations": "注釈",
"Show Results": "結果を表示",
"Clear search": "検索をクリア",
"Clear search history": "検索履歴をクリア",
"Tap to Toggle Footer": "タップでフッターを切り替え",
"Show Current Time": "現在時刻を表示",
"Use 24 Hour Clock": "24時間表示を使用",
"Show Current Battery Status": "バッテリー残量を表示",
"Exported successfully": "エクスポート成功",
"Book exported successfully.": "書籍のエクスポートに成功しました。",
"Failed to export the book.": "書籍のエクスポートに失敗しました。",
"Export Book": "書籍をエクスポート",
"Whole word:": "単語全体:",
"Error": "エラー",
"Unable to load the article. Try searching directly on {{link}}.": "記事を読み込めません。{{link}}で直接検索してみてください。",
"Unable to load the word. Try searching directly on {{link}}.": "単語を読み込めません。{{link}}で直接検索してみてください。",
"Date Published": "出版日",
"Only for TTS:": "TTSのみ:",
"Uploaded": "アップロード済み",
"Downloaded": "ダウンロード済み",
"Deleted": "削除済み",
"Note:": "ノート:",
"Time:": "時刻:",
"Format Options": "形式オプション",
"Export Date": "エクスポート日",
"Chapter Titles": "章タイトル",
"Chapter Separator": "章区切り",
"Highlights": "ハイライト",
"Note Date": "ノート日付",
"Advanced": "詳細設定",
"Hide": "非表示",
"Show": "表示",
"Use Custom Template": "カスタムテンプレート使用",
"Export Template": "エクスポートテンプレート",
"Template Syntax:": "テンプレート構文:",
"Insert value": "値を挿入",
"Format date (locale)": "日付形式(ロケール)",
"Format date (custom)": "日付形式(カスタム)",
"Conditional": "条件分岐",
"Loop": "ループ",
"Available Variables:": "利用可能な変数:",
"Book title": "本のタイトル",
"Book author": "著者",
"Export date": "エクスポート日",
"Array of chapters": "章の配列",
"Chapter title": "章タイトル",
"Array of annotations": "注釈の配列",
"Highlighted text": "ハイライトテキスト",
"Annotation note": "注釈ノート",
"Date Format Tokens:": "日付形式トークン:",
"Year (4 digits)": "年(4桁)",
"Month (01-12)": "月(01-12)",
"Day (01-31)": "日(01-31)",
"Hour (00-23)": "時(00-23)",
"Minute (00-59)": "分(00-59)",
"Second (00-59)": "秒(00-59)",
"Show Source": "ソース表示",
"No content to preview": "プレビューするコンテンツがありません",
"Export": "エクスポート",
"Set Timeout": "タイムアウト設定",
"Select Voice": "音声選択",
"Toggle Sticky Bottom TTS Bar": "TTSバー固定切替",
"Display what I'm reading on Discord": "読書中の本をDiscordに表示",
"Show on Discord": "Discordに表示",
"Instant {{action}}": "インスタント{{action}}",
"Instant {{action}} Disabled": "インスタント{{action}}を無効化",
"Annotation": "注釈",
"Reset Template": "テンプレートをリセット",
"Annotation style": "注釈スタイル",
"Annotation color": "注釈の色",
"Annotation time": "注釈時間",
"AI": "AI",
"Are you sure you want to re-index this book?": "この本を再インデックスしてもよろしいですか?",
"Enable AI in Settings": "設定でAIを有効にする",
"Index This Book": "この本をインデックス",
"Enable AI search and chat for this book": "この本のAI検索とチャットを有効にする",
"Start Indexing": "インデックス開始",
"Indexing book...": "本をインデックス中...",
"Preparing...": "準備中...",
"Delete this conversation?": "この会話を削除しますか?",
"No conversations yet": "まだ会話がありません",
"Start a new chat to ask questions about this book": "この本について質問するには新しいチャットを開始してください",
"Rename": "名前を変更",
"New Chat": "新しいチャット",
"Chat": "チャット",
"Please enter a model ID": "モデルIDを入力してください",
"Model not available or invalid": "モデルが利用できないか無効です",
"Failed to validate model": "モデルの検証に失敗しました",
"Couldn't connect to Ollama. Is it running?": "Ollamaに接続できませんでした。実行中ですか?",
"Invalid API key or connection failed": "APIキーが無効か接続に失敗しました",
"Connection failed": "接続に失敗しました",
"AI Assistant": "AIアシスタント",
"Enable AI Assistant": "AIアシスタントを有効にする",
"Provider": "プロバイダー",
"Ollama (Local)": "Ollama(ローカル)",
"AI Gateway (Cloud)": "AIゲートウェイ(クラウド)",
"Ollama Configuration": "Ollama設定",
"Refresh Models": "モデルを更新",
"AI Model": "AIモデル",
"No models detected": "モデルが検出されませんでした",
"AI Gateway Configuration": "AIゲートウェイ設定",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "高品質で経済的なAIモデルからお選びください。下の「カスタムモデル」を選択して独自のモデルを使用することもできます。",
"API Key": "APIキー",
"Get Key": "キーを取得",
"Model": "モデル",
"Custom Model...": "カスタムモデル...",
"Custom Model ID": "カスタムモデルID",
"Validate": "検証",
"Model available": "モデルが利用可能",
"Connection": "接続",
"Test Connection": "接続をテスト",
"Connected": "接続済み",
"Custom Colors": "カスタムカラー",
"Color E-Ink Mode": "カラー電子ペーパーモード",
"Reading Ruler": "リーディングルーラー",
"Enable Reading Ruler": "リーディングルーラーを有効にする",
"Lines to Highlight": "ハイライトする行数",
"Ruler Color": "ルーラーの色",
"Command Palette": "コマンドパレット",
"Search settings and actions...": "設定とアクションを検索...",
"No results found for": "の結果が見つかりませんでした",
"Type to search settings and actions": "入力して設定とアクションを検索",
"Recent": "最近使った項目",
"navigate": "ナビゲート",
"select": "選択",
"close": "閉じる",
"Search Settings": "設定を検索",
"Page Margins": "ページ余白",
"AI Provider": "AIプロバイダー",
"Ollama URL": "OllamaのURL",
"Ollama Model": "Ollamaモデル",
"AI Gateway Model": "AI Gatewayモデル",
"Actions": "アクション",
"Navigation": "ナビゲーション",
"Set status for {{count}} book(s)_other": "{{count}} 冊の本のステータスを設定",
"Mark as Unread": "未読にする",
"Mark as Finished": "読了にする",
"Finished": "読了",
"Unread": "未読",
"Clear Status": "ステータスをクリア",
"Status": "ステータス",
"Loading": "読み込み中",
"Exit Paragraph Mode": "段落モードを終了",
"Paragraph Mode": "段落モード",
"Embedding Model": "埋め込みモデル",
"{{count}} book(s) synced_other": "{{count}} 冊の本が同期されました",
"Unable to start RSVP": "RSVPを起動できません",
"RSVP not supported for PDF": "PDFはRSVPに対応していません",
"Select Chapter": "章を選択",
"Context": "コンテキスト",
"Ready": "準備完了",
"Chapter Progress": "章の進捗",
"words": "単語",
"{{time}} left": "残り {{time}}",
"Reading progress": "読書の進捗",
"Skip back 15 words": "15単語戻る",
"Back 15 words (Shift+Left)": "15単語戻る (Shift+左)",
"Pause (Space)": "一時停止 (Space)",
"Play (Space)": "再生 (Space)",
"Skip forward 15 words": "15単語進む",
"Forward 15 words (Shift+Right)": "15単語進む (Shift+右)",
"Decrease speed": "速度を下げる",
"Slower (Left/Down)": "低速 (左/下)",
"Increase speed": "速度を上げる",
"Faster (Right/Up)": "高速 (右/上)",
"Start RSVP Reading": "RSVP読書を開始",
"Choose where to start reading": "読書を開始する場所を選択",
"From Chapter Start": "章の最初から",
"Start reading from the beginning of the chapter": "この章の最初から読み直す",
"Resume": "再開",
"Continue from where you left off": "中断した場所から再開する",
"From Current Page": "現在のページから",
"Start from where you are currently reading": "現在読んでいる場所から開始する",
"From Selection": "選択範囲から",
"Speed Reading Mode": "速読モード",
"Scroll left": "左にスクロール",
"Scroll right": "右にスクロール",
"Library Sync Progress": "ライブラリ同期の進捗",
"Back to library": "ライブラリに戻る",
"Group by...": "グループ化...",
"Export as Plain Text": "プレーンテキストとして書き出し",
"Export as Markdown": "Markdownとして書き出し",
"Show Page Navigation Buttons": "ナビゲーションボタンを表示",
"Page {{number}}": "{{number}} ページ",
"highlight": "ハイライト",
"underline": "下線",
"squiggly": "波線",
"red": "赤",
"violet": "すみれ色",
"blue": "青",
"green": "緑",
"yellow": "黄色",
"Select {{style}} style": "スタイル {{style}} を選択",
"Select {{color}} color": "色 {{color}} を選択",
"Close Book": "本を閉じる",
"Speed Reading": "速読",
"Close Speed Reading": "速読を閉じる",
"Authors": "著者",
"Books": "書籍",
"Groups": "グループ",
"Back to TTS Location": "TTSの位置に戻る",
"Metadata": "メタデータ",
"Image viewer": "画像ビューア",
"Previous Image": "前の画像",
"Next Image": "次の画像",
"Zoomed": "ズーム済み",
"Zoom level": "ズームレベル",
"Table viewer": "テーブルビューア",
"Unable to connect to Readwise. Please check your network connection.": "Readwise に接続できません。ネットワーク接続を確認してください。",
"Invalid Readwise access token": "無効な Readwise アクセストークン",
"Disconnected from Readwise": "Readwise から切断されました",
"Never": "一度もなし",
"Readwise Settings": "Readwise 設定",
"Connected to Readwise": "Readwise に接続済み",
"Last synced: {{time}}": "最終同期:{{time}}",
"Sync Enabled": "同期有効",
"Disconnect": "切断",
"Connect your Readwise account to sync highlights.": "ハイライトを同期するには Readwise アカウントを接続してください。",
"Get your access token at": "アクセストークンの取得先:",
"Access Token": "アクセストークン",
"Paste your Readwise access token": "Readwise アクセストークンを貼り付けてください",
"Config": "設定",
"Readwise Sync": "Readwise 同期",
"Push Highlights": "ハイライトをプッシュ",
"Highlights synced to Readwise": "ハイライトが Readwise に同期されました",
"Readwise sync failed: no internet connection": "Readwise 同期失敗:インターネット接続がありません",
"Readwise sync failed: {{error}}": "Readwise 同期失敗:{{error}}",
"System Screen Brightness": "システムの画面の明るさ",
"Page:": "ページ:",
"Page: {{number}}": "ページ: {{number}}",
"Annotation page number": "注釈のページ番号",
"Translating...": "翻訳中...",
"Show Battery Percentage": "バッテリー残量を表示",
"Hide Scrollbar": "スクロールバーを非表示",
"Skip to last reading position": "最後の読書位置へ移動",
"Show context": "コンテキストを表示",
"Hide context": "コンテキストを非表示",
"Decrease font size": "文字サイズを縮小",
"Increase font size": "文字サイズを拡大",
"Focus": "フォーカス",
"Theme color": "テーマカラー",
"Import failed": "インポートに失敗しました",
"Available Formatters:": "利用可能なフォーマッター:",
"Format date": "日付のフォーマット",
"Markdown block quote (> per line)": "Markdown引用ブロック (行ごとに >)",
"Newlines to <br>": "改行を <br> に変換",
"Change case": "大文字/小文字の変更",
"Trim whitespace": "空白を除去",
"Truncate to n characters": "n文字に切り詰め",
"Replace text": "テキストを置換",
"Fallback value": "フォールバック値",
"Get length": "長さを取得",
"First/last element": "最初/最後の要素",
"Join array": "配列を結合",
"Backup failed: {{error}}": "バックアップに失敗しました: {{error}}",
"Select Backup": "バックアップを選択",
"Restore failed: {{error}}": "復元に失敗しました: {{error}}",
"Backup & Restore": "バックアップと復元",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "ライブラリのバックアップを作成するか、以前のバックアップから復元します。復元は現在のライブラリとマージされます。",
"Backup Library": "ライブラリをバックアップ",
"Restore Library": "ライブラリを復元",
"Creating backup...": "バックアップを作成中...",
"Restoring library...": "ライブラリを復元中...",
"{{current}} of {{total}} items": "{{current}} / {{total}} 件",
"Backup completed successfully!": "バックアップが完了しました!",
"Restore completed successfully!": "復元が完了しました!",
"Your library has been saved to the selected location.": "ライブラリが選択した場所に保存されました。",
"{{added}} books added, {{updated}} books updated.": "{{added}}冊追加、{{updated}}冊更新されました。",
"Operation failed": "操作に失敗しました",
"Loading library...": "ライブラリを読み込み中...",
"{{count}} books refreshed_other": "{{count}}冊のメタデータを更新しました",
"Failed to refresh metadata": "メタデータの更新に失敗しました",
"Refresh Metadata": "メタデータを更新",
"Keyboard Shortcuts": "キーボードショートカット",
"View all keyboard shortcuts": "すべてのキーボードショートカットを表示",
"Switch Sidebar Tab": "サイドバータブを切り替え",
"Toggle Notebook": "ノートブックの表示/非表示",
"Search in Book": "本の中を検索",
"Toggle Scroll Mode": "スクロールモードの切り替え",
"Toggle Select Mode": "選択モードの切り替え",
"Toggle Bookmark": "ブックマークの切り替え",
"Toggle Text to Speech": "音声読み上げの切り替え",
"Play / Pause TTS": "読み上げ再生 / 一時停止",
"Toggle Paragraph Mode": "段落モードの切り替え",
"Highlight Selection": "選択範囲をハイライト",
"Underline Selection": "選択範囲に下線",
"Annotate Selection": "選択範囲に注釈",
"Search Selection": "選択範囲を検索",
"Copy Selection": "選択範囲をコピー",
"Translate Selection": "選択範囲を翻訳",
"Dictionary Lookup": "辞書で調べる",
"Wikipedia Lookup": "Wikipediaで調べる",
"Read Aloud Selection": "選択範囲を読み上げ",
"Proofread Selection": "選択範囲を校正",
"Open Settings": "設定を開く",
"Open Command Palette": "コマンドパレットを開く",
"Show Keyboard Shortcuts": "キーボードショートカットを表示",
"Open Books": "本を開く",
"Toggle Fullscreen": "フルスクリーンの切り替え",
"Close Window": "ウィンドウを閉じる",
"Quit App": "アプリを終了",
"Go Left / Previous Page": "左へ / 前のページ",
"Go Right / Next Page": "右へ / 次のページ",
"Go Up": "上へ",
"Go Down": "下へ",
"Previous Chapter": "前の章",
"Next Chapter": "次の章",
"Scroll Half Page Down": "半ページ下にスクロール",
"Scroll Half Page Up": "半ページ上にスクロール",
"Save Note": "メモを保存",
"Single Section Scroll": "単一セクションスクロール",
"General": "一般",
"Text to Speech": "テキスト読み上げ",
"Zoom": "ズーム",
"Window": "ウィンドウ",
"Your Bookshelf": "あなたの本棚",
"TTS": "読み上げ",
"Media Info": "メディア情報",
"Update Frequency": "更新頻度",
"Every Sentence": "文ごと",
"Every Paragraph": "段落ごと",
"Every Chapter": "章ごと",
"TTS Media Info Update Frequency": "TTSメディア情報の更新頻度",
"Select reading speed": "読み上げ速度を選択",
"Drag to seek": "ドラッグしてシーク",
"Punctuation Delay": "句読点の遅延",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "続行する前に、このOPDS接続がWebアプリのReadestサーバーを経由してプロキシされることを確認してください。",
"Custom Headers": "カスタムヘッダー",
"Custom Headers (optional)": "カスタムヘッダー(任意)",
"Add one header per line using \"Header-Name: value\".": "「Header-Name: value」の形式で1行に1つのヘッダーを追加してください。",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "このOPDS接続がWebアプリのReadestサーバーを経由してプロキシされることを理解しています。これらの認証情報やヘッダーについてReadestを信頼しない場合は、ネイティブアプリを使用してください。",
"Unable to connect to Hardcover. Please check your network connection.": "Hardcoverに接続できません。ネットワーク接続を確認してください。",
"Invalid Hardcover API token": "Hardcover APIトークンが無効です",
"Disconnected from Hardcover": "Hardcoverから切断されました",
"Hardcover Settings": "Hardcover設定",
"Connected to Hardcover": "Hardcoverに接続済み",
"Connect your Hardcover account to sync reading progress and notes.": "Hardcoverアカウントを接続して、読書の進捗やメモを同期しましょう。",
"Get your API token from hardcover.app → Settings → API.": "hardcover.app → 設定 → APIからAPIトークンを取得してください。",
"API Token": "APIトークン",
"Paste your Hardcover API token": "HardcoverのAPIトークンを貼り付け",
"Hardcover sync enabled for this book": "この本のHardcover同期が有効になりました",
"Hardcover sync disabled for this book": "この本のHardcover同期が無効になりました",
"Hardcover Sync": "Hardcover同期",
"Enable for This Book": "この本で有効にする",
"Push Notes": "メモを送信",
"Enable Hardcover sync for this book first.": "まずこの本のHardcover同期を有効にしてください。",
"No annotations or excerpts to sync for this book.": "この本に同期する注釈や抜粋がありません。",
"Configure Hardcover in Settings first.": "まず設定でHardcoverを構成してください。",
"No new Hardcover note changes to sync.": "同期するHardcoverメモの新しい変更はありません。",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover同期完了: {{inserted}}件追加、{{updated}}件更新、{{skipped}}件変更なし",
"Hardcover notes sync failed: {{error}}": "Hardcoverメモの同期に失敗: {{error}}",
"Reading progress synced to Hardcover": "読書の進捗がHardcoverに同期されました",
"Hardcover progress sync failed: {{error}}": "Hardcover進捗の同期に失敗: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "既存のソース識別子を保持",
"Toggle Toolbar": "ツールバーの表示切替"
}
@@ -8,7 +8,6 @@
"Auto Mode": "자동 모드",
"Behavior": "동작",
"Book": "책",
"Book Cover": "책 표지",
"Bookmark": "북마크",
"Cancel": "취소",
"Chapter": "챕터",
@@ -46,7 +45,6 @@
"Horizontal Direction": "수평 방향",
"Hyphenation": "하이픈 넣기",
"Import Books": "책 가져오기",
"Language:": "언어:",
"Layout": "레이아웃",
"Light Mode": "라이트 모드",
"Loading...": "로딩 중...",
@@ -68,8 +66,8 @@
"Paging Animation": "페이지 넘김 애니메이션",
"Paragraph": "단락",
"Parallel Read": "병렬 읽기",
"Published:": "출판일:",
"Publisher:": "출판사:",
"Published": "출판일",
"Publisher": "출판사",
"Reading Progress Synced": "읽기 진행 상황 동기화됨",
"Reload Page": "페이지 새로고침",
"Reveal in File Explorer": "파일 탐색기에서 표시",
@@ -83,7 +81,6 @@
"Search...": "검색...",
"Select Book": "책 선택",
"Select Books": "책 선택",
"Select Multiple Books": "여러 책 선택",
"Sepia": "세피아",
"Serif Font": "세리프체",
"Show Book Details": "책 세부 정보 표시",
@@ -94,23 +91,21 @@
"Slow": "느림",
"Solarized": "솔라라이즈드",
"Speak": "말하기",
"Subjects:": "주제:",
"Subjects": "주제",
"System Fonts": "시스템 글꼴",
"TTS not supported in this device": "이 장치에서 TTS가 지원되지 않음",
"Theme Color": "테마 색상",
"Theme Mode": "테마 모드",
"Translate": "번역",
"Translated Text": "번역된 텍스트",
"Unknown": "알 수 없음",
"Untitled": "제목 없음",
"Updated:": "업데이트일:",
"Updated": "업데이트일",
"Version {{version}}": "버전 {{version}}",
"Vertical Direction": "수직 방향",
"Welcome to your library. You can import your books here and read them anytime.": "내 서재에 오신 것을 환영합니다. 여기에서 책을 가져와 언제든지 읽을 수 있습니다.",
"Wikipedia": "위키피디아",
"Writing Mode": "글쓰기 모드",
"Your Library": "내 서재",
"TTS not supported for PDF": "PDF에서 TTS가 지원되지 않음",
"Override Book Font": "책 글꼴 덮어쓰기",
"Apply to All Books": "모든 책에 적용",
"Apply to This Book": "이 책에 적용",
@@ -120,6 +115,7 @@
"Book Details": "책 세부 정보",
"From Local File": "로컬 파일에서",
"TOC": "목차",
"Table of Contents": "목차",
"Book uploaded: {{title}}": "책 업로드됨: {{title}}",
"Failed to upload book: {{title}}": "책 업로드 실패: {{title}}",
"Book downloaded: {{title}}": "책 다운로드됨: {{title}}",
@@ -176,9 +172,6 @@
"Token": "토큰",
"Your OTP token": "당신의 OTP 토큰",
"Verify token": "토큰 확인",
"Sign in with Google": "Google로 로그인",
"Sign in with Apple": "Apple로 로그인",
"Sign in with GitHub": "GitHub로 로그인",
"Account": "계정",
"Failed to delete user. Please try again later.": "사용자 삭제에 실패했습니다. 나중에 다시 시도해 주세요.",
"Community Support": "커뮤니티 지원",
@@ -191,12 +184,11 @@
"RTL Direction": "RTL 방향",
"Maximum Column Height": "최대 열 높이",
"Maximum Column Width": "최대 열 너비",
"Continuous Scroll": "연속 스크롤",
"Fullscreen": "전체 화면",
"No supported files found. Supported formats: {{formats}}": "지원되는 파일이 없습니다. 지원되는 형식: {{formats}}",
"Drop to Import Books": "책 가져오기 위해 드롭",
"Custom": "사용자 정의",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "세상은 무대이며,\n그리고 모든 남자와 여자는 단지 배우일 뿐입니다;\n그들은 나가는 곳과 들어오는 곳이 있으며,\n그리고 한 남자는 그의 시간에 많은 역할을 합니다,\n그의 행동은 일곱 시대입니다.\n\n— 윌리엄 셰익스피어",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "세상은 무대이며,\n그리고 모든 남자와 여자는 단지 배우일 뿐입니다;\n그들은 나가는 곳과 들어오는 곳이 있으며,\n그리고 한 남자는 그의 시간에 많은 역할을 합니다,\n그의 행동은 일곱 시대입니다.\n\n— 윌리엄 셰익스피어",
"Custom Theme": "사용자 정의 테마",
"Theme Name": "테마 이름",
"Text Color": "텍스트 색상",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "파일 열 때 자동 가져오기",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "장 발견되지 않음.",
"Failed to parse the EPUB file.": "EPUB 파일 구문 분석 실패.",
"This book format is not supported.": "이 책 형식은 지원되지 않습니다.",
"No chapters detected": "장 발견되지 않음",
"Failed to parse the EPUB file": "EPUB 파일 구문 분석 실패",
"This book format is not supported": "이 책 형식은 지원되지 않습니다",
"Unable to fetch the translation. Please log in first and try again.": "번역을 가져올 수 없습니다. 먼저 로그인하고 다시 시도하세요.",
"Group": "그룹",
"Always on Top": "항상 위에",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "다운로드 중 {{downloaded}} / {{contentLength}}",
"Download finished": "다운로드 완료",
"DOWNLOAD & INSTALL": "다운로드 및 설치",
"Changelog:": "변경 로그:",
"Changelog": "변경 로그",
"Software Update": "소프트웨어 업데이트",
"Title": "제목",
"Date Read": "읽은 날짜",
@@ -253,18 +245,15 @@
"Ascending": "오름차순",
"Descending": "내림차순",
"Sort by...": "정렬 기준...",
"Added:": "추가됨:",
"Format:": "형식:",
"Added": "추가됨",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "설명:",
"Description": "설명",
"No description available": "설명 없음",
"List": "목록",
"Grid": "격자",
"(from 'As You Like It', Act II)": "(당신이 좋아하는 대로, 2막)",
"Link Color": "링크 색상",
"Volume Keys for Page Flip": "페이지 넘김을 위한 볼륨 키",
"Clicks for Page Flip": "페이지 넘김을 위한 클릭",
"Swap Clicks Area": "클릭 영역 교환",
"Screen": "화면",
"Orientation": "방향",
"Portrait": "세로",
@@ -273,7 +262,7 @@
"Checking for updates...": "업데이트 확인 중...",
"Error checking for updates": "업데이트 확인 중 오류 발생",
"Details": "세부정보",
"File Size:": "파일 크기:",
"File Size": "파일 크기",
"Auto Detect": "자동 감지",
"Next Section": "다음 섹션",
"Previous Section": "이전 섹션",
@@ -299,7 +288,6 @@
"Disable Translation": "번역 비활성화",
"Scroll": "스크롤",
"Overlap Pixels": "겹치는 픽셀",
"Click": "클릭",
"System Language": "시스템 언어",
"Security": "보안",
"Allow JavaScript": "JavaScript 허용",
@@ -312,7 +300,6 @@
"Synced at {{time}}": "{{time}}에 동기화됨",
"Never synced": "동기화된 적 없음",
"Show Remaining Time": "남은 시간 표시",
"Show Page Number": "페이지 번호 표시",
"{{time}} min left in chapter": "{{time}}분 남음",
"Override Book Color": "책 색상 덮어쓰기",
"Login Required": "로그인 필요",
@@ -334,7 +321,6 @@
"Left Margin (px)": "왼쪽 여백 (px)",
"Column Gap (%)": "열 간격 (%)",
"Always Show Status Bar": "상태 표시줄 항상 표시",
"Translation Not Available": "번역을 사용할 수 없음",
"Custom Content CSS": "콘텐츠 CSS",
"Enter CSS for book content styling...": "도서 콘텐츠 스타일을 위한 CSS 입력...",
"Custom Reader UI CSS": "리더 UI CSS",
@@ -344,10 +330,10 @@
"Fit": "맞춤",
"Reset {{settings}}": "{{settings}} 재설정",
"Reset Settings": "설정 재설정",
"{{count}} pages left in chapter_other": "남은 페이지 {{count}}",
"{{count}} pages left in chapter_other": "<1>남은 페이지 </1><0>{{count}}</0><1>장</1>",
"Show Remaining Pages": "남은 페이지 보기",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "구독 관리",
"Coming Soon": "곧 출시 예정",
@@ -355,7 +341,6 @@
"Upgrade to Plus or Pro": "Plus 또는 Pro로 업그레이드",
"Current Plan": "현재 요금제",
"Plan Limits": "요금제 한도",
"Failed to manage subscription. Please try again later.": "구독 관리에 실패했습니다. 나중에 다시 시도해주세요.",
"Processing your payment...": "결제를 처리 중입니다...",
"Please wait while we confirm your subscription.": "구독을 확인하는 중입니다. 잠시만 기다려주세요.",
"Payment Processing": "결제 처리 중",
@@ -368,7 +353,6 @@
"Email:": "이메일:",
"Plan:": "요금제:",
"Amount:": "금액:",
"Subscription ID:": "구독 ID:",
"Go to Library": "라이브러리로 이동",
"Need help? Contact our support team at support@readest.com": "도움이 필요하시면 support@readest.com으로 문의해주세요.",
"Free Plan": "무료 요금제",
@@ -398,7 +382,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "제한 없이 텍스트를 음성으로 변환하세요.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "고급 번역 기능을 더 많이 이용하세요.",
"DeepL Pro Access": "DeepL Pro 이용",
"2 GB Cloud Sync Storage": "2GB 클라우드 저장소",
"Enjoy faster responses and dedicated assistance whenever you need help.": "우선 지원을 이용하세요.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "일일 번역 한도에 도달했습니다. 업그레이드하여 계속 사용하세요.",
"Includes All Plus Plan Benefits": "모든 플러스 플랜 혜택 포함",
@@ -408,10 +391,784 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "스마트한 독서, 번역, 콘텐츠 발견을 위한 강력한 AI 도구를 활용하세요.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "가장 정확한 번역 엔진으로 매일 최대 10만 자를 번역하세요.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "가장 정확한 번역 엔진으로 매일 최대 50만 자를 번역하세요.",
"10 GB Cloud Sync Storage": "10GB 클라우드 동기화 저장소",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "최대 2GB의 안전한 클라우드 저장소로 전체 독서 컬렉션을 저장하고 액세스하세요.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "최대 10GB의 안전한 클라우드 저장소로 전체 독서 컬렉션을 저장하고 액세스하세요.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "최대 5GB의 안전한 클라우드 저장소로 전체 독서 컬렉션을 저장하고 액세스하세요.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "최대 20GB의 안전한 클라우드 저장소로 전체 독서 컬렉션을 저장하고 액세스하세요.",
"Deleted cloud backup of the book: {{title}}": "책의 클라우드 백업이 삭제됨: {{title}}",
"Failed to delete cloud backup of the book": "책의 클라우드 백업을 삭제하지 못했습니다.",
"Are you sure to delete the cloud backup of the selected book?": "선택한 책의 클라우드 백업을 삭제하시겠습니까?"
"Are you sure to delete the cloud backup of the selected book?": "선택한 책의 클라우드 백업을 삭제하시겠습니까?",
"What's New in Readest": "Readest의 새로운 기능",
"Enter book title": "도서 제목 입력",
"Subtitle": "부제목",
"Enter book subtitle": "도서 부제목 입력",
"Enter author name": "저자명 입력",
"Series": "시리즈",
"Enter series name": "시리즈명 입력",
"Series Index": "시리즈 번호",
"Enter series index": "시리즈 번호 입력",
"Total in Series": "시리즈 총권수",
"Enter total books in series": "시리즈 총 도서 수 입력",
"Enter publisher": "출판사 입력",
"Publication Date": "출간일",
"Identifier": "식별자",
"Enter book description": "도서 설명 입력",
"Change cover image": "표지 이미지 변경",
"Replace": "교체",
"Unlock cover": "표지 잠금 해제",
"Lock cover": "표지 잠금",
"Auto-Retrieve Metadata": "메타데이터 자동 검색",
"Auto-Retrieve": "자동 검색",
"Unlock all fields": "모든 필드 잠금 해제",
"Unlock All": "모두 잠금 해제",
"Lock all fields": "모든 필드 잠금",
"Lock All": "모두 잠금",
"Reset": "초기화",
"Edit Metadata": "메타데이터 편집",
"Locked": "잠김",
"Select Metadata Source": "메타데이터 소스 선택",
"Keep manual input": "수동 입력 유지",
"Google Books": "구글 북스",
"Open Library": "오픈 라이브러리",
"Fiction, Science, History": "소설, 과학, 역사",
"Open Book in New Window": "새 창에서 책 열기",
"Voices for {{lang}}": "{{lang}}의 음성",
"Yandex Translate": "Yandex 번역",
"YYYY or YYYY-MM-DD": "YYYY 또는 YYYY-MM-DD",
"Restore Purchase": "구매 복원",
"No purchases found to restore.": "복원할 구매가 없습니다.",
"Failed to restore purchases.": "구매 복원에 실패했습니다.",
"Failed to manage subscription.": "구독 관리에 실패했습니다.",
"Failed to load subscription plans.": "구독 플랜 로드에 실패했습니다.",
"year": "년",
"Failed to create checkout session": "체크아웃 세션 생성 실패",
"Storage": "저장소",
"Terms of Service": "서비스 약관",
"Privacy Policy": "개인정보 보호정책",
"Disable Double Click": "더블 클릭 비활성화",
"TTS not supported for this document": "TTS가 이 문서에서 지원되지 않습니다",
"Reset Password": "비밀번호 재설정",
"Show Reading Progress": "읽기 진행 상황 표시",
"Reading Progress Style": "읽기 진행 상황 스타일",
"Page Number": "페이지 번호",
"Percentage": "백분율",
"Deleted local copy of the book: {{title}}": "책의 로컬 사본이 삭제됨: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "책의 클라우드 백업 삭제에 실패했습니다: {{title}}",
"Failed to delete local copy of the book: {{title}}": "책의 로컬 사본 삭제에 실패했습니다: {{title}}",
"Are you sure to delete the local copy of the selected book?": "선택한 책의 로컬 사본을 삭제하시겠습니까?",
"Remove from Cloud & Device": "클라우드 및 장치에서 제거",
"Remove from Cloud Only": "클라우드에서만 제거",
"Remove from Device Only": "장치에서만 제거",
"Disconnected": "연결 끊김",
"KOReader Sync Settings": "KOReader Sync 설정",
"Sync Strategy": "동기화 전략",
"Ask on conflict": "충돌 시 묻기",
"Always use latest": "항상 최신 버전 사용",
"Send changes only": "변경 사항만 전송",
"Receive changes only": "변경 사항만 수신",
"Checksum Method": "체크섬 방법",
"File Content (recommended)": "파일 내용 (권장)",
"File Name": "파일 이름",
"Device Name": "장치 이름",
"Connect to your KOReader Sync server.": "KOReader Sync 서버에 연결합니다.",
"Server URL": "서버 URL",
"Username": "사용자 이름",
"Your Username": "당신의 사용자 이름",
"Password": "비밀번호",
"Connect": "연결",
"KOReader Sync": "KOReader Sync",
"Sync Conflict": "동기화 충돌",
"Sync reading progress from \"{{deviceName}}\"?": " \"{{deviceName}}\"에서 읽기 진행 상황을 동기화하시겠습니까?",
"another device": "다른 장치",
"Local Progress": "로컬 진행 상황",
"Remote Progress": "원격 진행 상황",
"Page {{page}} of {{total}} ({{percentage}}%)": "페이지 {{page}} / {{total}} ({{percentage}}%)",
"Current position": "현재 위치",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "대략 페이지 {{page}} / {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "대략 {{percentage}}%",
"Failed to connect": "연결 실패",
"Sync Server Connected": "동기화 서버에 연결됨",
"Sync as {{userDisplayName}}": "{{userDisplayName}}로 동기화",
"Custom Fonts": "사용자 정의 글꼴",
"Cancel Delete": "삭제 취소",
"Import Font": "글꼴 가져오기",
"Delete Font": "글꼴 삭제",
"Tips": "팁",
"Custom fonts can be selected from the Font Face menu": "사용자 정의 글꼴은 글꼴 메뉴에서 선택할 수 있습니다",
"Manage Custom Fonts": "사용자 정의 글꼴 관리",
"Select Files": "파일 선택",
"Select Image": "이미지 선택",
"Select Video": "동영상 선택",
"Select Audio": "오디오 선택",
"Select Fonts": "글꼴 선택",
"Supported font formats: .ttf, .otf, .woff, .woff2": "지원되는 글꼴 형식: .ttf, .otf, .woff, .woff2",
"Push Progress": "진행 상황 푸시",
"Pull Progress": "진행 상황 끌어오기",
"Previous Paragraph": "이전 단락",
"Previous Sentence": "이전 문장",
"Pause": "일시정지",
"Play": "재생",
"Next Sentence": "다음 문장",
"Next Paragraph": "다음 단락",
"Separate Cover Page": "별도의 표지 페이지",
"Resize Notebook": "노트북 크기 조정",
"Resize Sidebar": "사이드바 크기 조정",
"Get Help from the Readest Community": "Readest 커뮤니티에서 도움 받기",
"Remove cover image": "표지 이미지 제거",
"Bookshelf": "책장",
"View Menu": "메뉴 보기",
"Settings Menu": "설정 메뉴",
"View account details and quota": "계정 세부정보 및 할당량 보기",
"Library Header": "라이브러리 헤더",
"Book Content": "도서 내용",
"Footer Bar": "푸터 바",
"Header Bar": "헤더 바",
"View Options": "보기 옵션",
"Book Menu": "도서 메뉴",
"Search Options": "검색 옵션",
"Close": "닫기",
"Delete Book Options": "도서 삭제 옵션",
"ON": "켜기",
"OFF": "끄기",
"Reading Progress": "읽기 진행 상황",
"Page Margin": "페이지 여백",
"Remove Bookmark": "북마크 제거",
"Add Bookmark": "북마크 추가",
"Books Content": "책 내용",
"Jump to Location": "위치로 이동",
"Unpin Notebook": "노트북 고정 해제",
"Pin Notebook": "노트북 고정",
"Hide Search Bar": "검색 바 숨기기",
"Show Search Bar": "검색 바 표시",
"On {{current}} of {{total}} page": "페이지 {{current}} / {{total}}",
"Section Title": "섹션 제목",
"Decrease": "감소",
"Increase": "증가",
"Settings Panels": "설정 패널",
"Settings": "설정",
"Unpin Sidebar": "사이드바 고정 해제",
"Pin Sidebar": "사이드바 고정",
"Toggle Sidebar": "사이드바 전환",
"Toggle Translation": "번역 전환",
"Translation Disabled": "번역 비활성화",
"Minimize": "최소화",
"Maximize or Restore": "최대화 또는 복원",
"Exit Parallel Read": "병렬 읽기 종료",
"Enter Parallel Read": "병렬 읽기 시작",
"Zoom Level": "확대/축소 수준",
"Zoom Out": "축소",
"Reset Zoom": "줌 재설정",
"Zoom In": "확대",
"Zoom Mode": "줌 모드",
"Single Page": "단일 페이지",
"Auto Spread": "자동 스프레드",
"Fit Page": "페이지에 맞춤",
"Fit Width": "너비에 맞춤",
"Failed to select directory": "디렉토리 선택 실패",
"The new data directory must be different from the current one.": "새 데이터 디렉토리는 현재 디렉토리와 달라야 합니다.",
"Migration failed: {{error}}": "마이그레이션 실패: {{error}}",
"Change Data Location": "데이터 위치 변경",
"Current Data Location": "현재 데이터 위치",
"Total size: {{size}}": "총 크기: {{size}}",
"Calculating file info...": "파일 정보 계산 중...",
"New Data Location": "새 데이터 위치",
"Choose Different Folder": "다른 폴더 선택",
"Choose New Folder": "새 폴더 선택",
"Migrating data...": "데이터 마이그레이션 중...",
"Copying: {{file}}": "복사 중: {{file}}",
"{{current}} of {{total}} files": "{{current}} / {{total}} 파일",
"Migration completed successfully!": "마이그레이션이 성공적으로 완료되었습니다!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "데이터가 새 위치로 이동되었습니다. 프로세스를 완료하려면 애플리케이션을 재시작하십시오.",
"Migration failed": "마이그레이션 실패",
"Important Notice": "중요한 공지",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "이 작업은 모든 앱 데이터를 새 위치로 이동합니다. 대상에 충분한 여유 공간이 있는지 확인하십시오.",
"Restart App": "앱 재시작",
"Start Migration": "마이그레이션 시작",
"Advanced Settings": "고급 설정",
"File count: {{size}}": "파일 수: {{size}}",
"Background Read Aloud": "백그라운드 음성 읽기",
"Ready to read aloud": "읽기 준비 완료",
"Read Aloud": "음성 읽기",
"Screen Brightness": "화면 밝기",
"Background Image": "배경 이미지",
"Import Image": "이미지 가져오기",
"Opacity": "불투명도",
"Size": "크기",
"Cover": "표지",
"Contain": "포함",
"{{number}} pages left in chapter": "<1>남은 페이지 </1><0>{{number}}</0><1>장</1>",
"Device": "장치",
"E-Ink Mode": "E-Ink 모드",
"Highlight Colors": "하이라이트 색상",
"Pagination": "페이지 매김",
"Disable Double Tap": "더블 탭 비활성화",
"Tap to Paginate": "탭하여 페이지 매김",
"Click to Paginate": "클릭하여 페이지 매김",
"Tap Both Sides": "양쪽을 탭",
"Click Both Sides": "양쪽을 클릭",
"Swap Tap Sides": "탭 사이드 전환",
"Swap Click Sides": "클릭 사이드 전환",
"Source and Translated": "원본 및 번역",
"Translated Only": "번역만",
"Source Only": "원본만",
"TTS Text": "TTS 텍스트",
"The book file is corrupted": "책 파일이 손상되었습니다",
"The book file is empty": "책 파일이 비어 있습니다",
"Failed to open the book file": "책 파일을 열지 못했습니다",
"On-Demand Purchase": "온디맨드 구매",
"Full Customization": "풀 커스터마이징",
"Lifetime Plan": "평생 플랜",
"One-Time Payment": "일회성 결제",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "모든 장치에서 특정 기능에 대한 평생 액세스를 즐기기 위해 단일 결제를 수행합니다. 필요할 때만 특정 기능이나 서비스를 구매합니다.",
"Expand Cloud Sync Storage": "클라우드 동기화 저장소 확장",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "1회 구매로 클라우드 저장소를 영구적으로 확장합니다. 추가 구매 시 더 많은 공간이 추가됩니다.",
"Unlock All Customization Options": "모든 커스터마이징 옵션 잠금 해제",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "추가 테마, 글꼴, 레이아웃 옵션 및 읽기, 번역기, 클라우드 스토리지 서비스를 잠금 해제합니다.",
"Purchase Successful!": "구매 성공!",
"lifetime": "평생",
"Thank you for your purchase! Your payment has been processed successfully.": "구매해주셔서 감사합니다! 결제가 성공적으로 처리되었습니다.",
"Order ID:": "주문 ID:",
"TTS Highlighting": "TTS 하이라이팅",
"Style": "스타일",
"Underline": "밑줄",
"Strikethrough": "취소선",
"Squiggly": "물결선",
"Outline": "윤곽선",
"Save Current Color": "현재 색상 저장",
"Quick Colors": "빠른 색상",
"Highlighter": "형광펜",
"Save Book Cover": "책 표지 저장",
"Auto-save last book cover": "마지막 책 표지 자동 저장",
"Back": "뒤로",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "확인 이메일이 전송되었습니다! 변경을 확인하려면 이전 이메일 주소와 새 이메일 주소를 확인하세요.",
"Failed to update email": "이메일 업데이트 실패",
"New Email": "새 이메일",
"Your new email": "새 이메일 주소",
"Updating email ...": "이메일 업데이트 중...",
"Update email": "이메일 업데이트",
"Current email": "현재 이메일",
"Update Email": "이메일 업데이트",
"All": "전체",
"Unable to open book": "책을 열 수 없습니다",
"Punctuation": "구두점",
"Replace Quotation Marks": "인용 부호 바꾸기",
"Enabled only in vertical layout.": "세로 레이아웃에서만 활성화됩니다.",
"No Conversion": "변환 없음",
"Simplified to Traditional": "간체 → 번체",
"Traditional to Simplified": "번체 → 간체",
"Simplified to Traditional (Taiwan)": "간체 → 번체 (대만)",
"Simplified to Traditional (Hong Kong)": "간체 → 번체 (홍콩)",
"Simplified to Traditional (Taiwan), with phrases": "간체 → 번체 (대만) • 문구",
"Traditional (Taiwan) to Simplified": "번체 (대만) → 간체",
"Traditional (Hong Kong) to Simplified": "번체 (홍콩) → 간체",
"Traditional (Taiwan) to Simplified, with phrases": "번체 (대만) → 간체 • 문구",
"Convert Simplified and Traditional Chinese": "간체/번체 변환",
"Convert Mode": "변환 모드",
"Failed to auto-save book cover for lock screen: {{error}}": "잠금 화면용 책 표지 자동 저장 실패: {{error}}",
"Download from Cloud": "클라우드에서 다운로드",
"Upload to Cloud": "클라우드에 업로드",
"Clear Custom Fonts": "사용자 정의 글꼴 지우기",
"Columns": "열",
"OPDS Catalogs": "OPDS 카탈로그",
"Adding LAN addresses is not supported in the web app version.": "웹 앱 버전에서는 LAN 주소 추가를 지원하지 않습니다.",
"Invalid OPDS catalog. Please check the URL.": "잘못된 OPDS 카탈로그입니다. URL을 확인해주세요.",
"Browse and download books from online catalogs": "온라인 카탈로그에서 책을 탐색하고 다운로드",
"My Catalogs": "내 카탈로그",
"Add Catalog": "카탈로그 추가",
"No catalogs yet": "아직 카탈로그가 없습니다",
"Add your first OPDS catalog to start browsing books": "책을 탐색하려면 첫 번째 OPDS 카탈로그를 추가하세요.",
"Add Your First Catalog": "첫 번째 카탈로그 추가",
"Browse": "탐색",
"Popular Catalogs": "인기 카탈로그",
"Add": "추가",
"Add OPDS Catalog": "OPDS 카탈로그 추가",
"Catalog Name": "카탈로그 이름",
"My Calibre Library": "내 Calibre 라이브러리",
"OPDS URL": "OPDS URL",
"Username (optional)": "사용자 이름 (선택 사항)",
"Password (optional)": "비밀번호 (선택 사항)",
"Description (optional)": "설명 (선택 사항)",
"A brief description of this catalog": "이 카탈로그의 간단한 설명",
"Validating...": "검증 중...",
"View All": "모두 보기",
"Forward": "다음",
"Home": "홈",
"{{count}} items_other": "{{count}}개 항목",
"Download completed": "다운로드 완료",
"Download failed": "다운로드 실패",
"Open Access": "오픈 액세스",
"Borrow": "대출",
"Buy": "구매",
"Subscribe": "구독",
"Sample": "샘플",
"Download": "다운로드",
"Open & Read": "열기 및 읽기",
"Tags": "태그",
"Tag": "태그",
"First": "처음",
"Previous": "이전",
"Next": "다음",
"Last": "마지막",
"Cannot Load Page": "페이지를 불러올 수 없습니다",
"An error occurred": "오류가 발생했습니다",
"Online Library": "온라인 라이브러리",
"URL must start with http:// or https://": "URL은 http:// 또는 https://로 시작해야 합니다",
"Title, Author, Tag, etc...": "제목, 저자, 태그 등...",
"Query": "쿼리",
"Subject": "주제",
"Enter {{terms}}": "{{terms}} 입력",
"No search results found": "검색 결과가 없습니다",
"Failed to load OPDS feed: {{status}} {{statusText}}": "OPDS 피드를 불러오지 못했습니다: {{status}} {{statusText}}",
"Search in {{title}}": "{{title}}에서 검색",
"Manage Storage": "저장소 관리",
"Failed to load files": "파일 로드 실패",
"Deleted {{count}} file(s)_other": "{{count}}개의 파일이 삭제되었습니다",
"Failed to delete {{count}} file(s)_other": "{{count}}개의 파일 삭제 실패",
"Failed to delete files": "파일 삭제 실패",
"Total Files": "총 파일",
"Total Size": "총 용량",
"Quota": "쿼터",
"Used": "사용됨",
"Files": "파일",
"Search files...": "파일 검색...",
"Newest First": "최신순",
"Oldest First": "오래된순",
"Largest First": "큰 파일순",
"Smallest First": "작은 파일순",
"Name A-Z": "이름 A-Z",
"Name Z-A": "이름 Z-A",
"{{count}} selected_other": "{{count}}개 선택됨",
"Delete Selected": "선택 삭제",
"Created": "생성됨",
"No files found": "파일이 없습니다",
"No files uploaded yet": "아직 업로드된 파일이 없습니다",
"files": "파일",
"Page {{current}} of {{total}}": "페이지 {{current}} / {{total}}",
"Are you sure to delete {{count}} selected file(s)?_other": "선택한 {{count}}개의 파일을 삭제하시겠습니까?",
"Cloud Storage Usage": "클라우드 저장소 사용량",
"Rename Group": "그룹 이름 바꾸기",
"From Directory": "디렉토리에서",
"Successfully imported {{count}} book(s)_other": "성공적으로 {{count}} 권의 책이 가져와졌습니다",
"Count": "개수",
"Start Page": "시작 페이지",
"Search in OPDS Catalog...": "OPDS 카탈로그에서 검색...",
"Please log in to use advanced TTS features": "고급 TTS 기능을 사용하려면 로그인하세요",
"Word limit of 30 words exceeded.": "30단어 제한을 초과했습니다.",
"Proofread": "교정",
"Current selection": "현재 선택",
"All occurrences in this book": "이 책의 모든 위치",
"All occurrences in your library": "라이브러리의 모든 위치",
"Selected text:": "선택한 텍스트:",
"Replace with:": "다음으로 바꾸기:",
"Enter text...": "텍스트 입력…",
"Case sensitive:": "대소문자 구분:",
"Scope:": "적용 범위:",
"Selection": "선택",
"Library": "라이브러리",
"Yes": "예",
"No": "아니요",
"Proofread Replacement Rules": "교정 대체 규칙",
"Selected Text Rules": "선택한 텍스트 규칙",
"No selected text replacement rules": "선택한 텍스트에 대한 대체 규칙이 없습니다",
"Book Specific Rules": "책별 규칙",
"No book-level replacement rules": "책 수준의 대체 규칙이 없습니다",
"Disable Quick Action": "빠른 작업 비활성화",
"Enable Quick Action on Selection": "선택 시 빠른 작업 활성화",
"None": "없음",
"Annotation Tools": "주석 도구",
"Enable Quick Actions": "빠른 작업 활성화",
"Quick Action": "빠른 작업",
"Copy to Notebook": "노트에 복사",
"Copy text after selection": "선택 후 텍스트 복사",
"Highlight text after selection": "선택 후 텍스트 강조",
"Annotate text after selection": "선택 후 텍스트 주석 달기",
"Search text after selection": "선택 후 텍스트 검색",
"Look up text in dictionary after selection": "선택 후 텍스트를 사전에서 찾기",
"Look up text in Wikipedia after selection": "선택 후 텍스트를 위키피디아에서 찾기",
"Translate text after selection": "선택 후 텍스트 번역",
"Read text aloud after selection": "선택 후 텍스트 음성 읽기",
"Proofread text after selection": "선택 후 텍스트 교정",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} 진행 중, {{pendingCount}} 대기 중",
"{{failedCount}} failed": "{{failedCount}} 실패",
"Waiting...": "대기 중...",
"Failed": "실패",
"Completed": "완료됨",
"Cancelled": "취소됨",
"Retry": "재시도",
"Active": "진행 중",
"Transfer Queue": "전송 대기열",
"Upload All": "모두 업로드",
"Download All": "모두 다운로드",
"Resume Transfers": "전송 재개",
"Pause Transfers": "전송 일시정지",
"Pending": "대기 중",
"No transfers": "전송 없음",
"Retry All": "모두 재시도",
"Clear Completed": "완료된 항목 지우기",
"Clear Failed": "실패한 항목 지우기",
"Upload queued: {{title}}": "업로드 대기열에 추가됨: {{title}}",
"Download queued: {{title}}": "다운로드 대기열에 추가됨: {{title}}",
"Book not found in library": "라이브러리에서 책을 찾을 수 없음",
"Unknown error": "알 수 없는 오류",
"Please log in to continue": "계속하려면 로그인하세요",
"Cloud File Transfers": "클라우드 파일 전송",
"Show Search Results": "검색 결과 보기",
"Search results for '{{term}}'": "'{{term}}' 검색 결과",
"Close Search": "검색 닫기",
"Previous Result": "이전 결과",
"Next Result": "다음 결과",
"Bookmarks": "북마크",
"Annotations": "주석",
"Show Results": "결과 표시",
"Clear search": "검색 지우기",
"Clear search history": "검색 기록 지우기",
"Tap to Toggle Footer": "탭하여 바닥글 전환",
"Show Current Time": "현재 시간 표시",
"Use 24 Hour Clock": "24시간제 사용",
"Show Current Battery Status": "현재 배터리 상태 표시",
"Exported successfully": "내보내기 성공",
"Book exported successfully.": "책을 성공적으로 내보냈습니다.",
"Failed to export the book.": "책 내보내기에 실패했습니다.",
"Export Book": "책 내보내기",
"Whole word:": "전체 단어:",
"Error": "오류",
"Unable to load the article. Try searching directly on {{link}}.": "문서를 로드할 수 없습니다. {{link}}에서 직접 검색해 보세요.",
"Unable to load the word. Try searching directly on {{link}}.": "단어를 로드할 수 없습니다. {{link}}에서 직접 검색해 보세요.",
"Date Published": "출판일",
"Only for TTS:": "TTS 전용:",
"Uploaded": "업로드됨",
"Downloaded": "다운로드됨",
"Deleted": "삭제됨",
"Note:": "노트:",
"Time:": "시간:",
"Format Options": "형식 옵션",
"Export Date": "내보내기 날짜",
"Chapter Titles": "챕터 제목",
"Chapter Separator": "챕터 구분 기호",
"Highlights": "하이라이트",
"Note Date": "노트 날짜",
"Advanced": "고급",
"Hide": "숨기기",
"Show": "표시",
"Use Custom Template": "사용자 지정 템플릿 사용",
"Export Template": "내보내기 템플릿",
"Template Syntax:": "템플릿 구문:",
"Insert value": "값 삽입",
"Format date (locale)": "날짜 형식 (로케일)",
"Format date (custom)": "날짜 형식 (사용자 지정)",
"Conditional": "조건부",
"Loop": "반복",
"Available Variables:": "사용 가능한 변수:",
"Book title": "책 제목",
"Book author": "책 저자",
"Export date": "내보내기 날짜",
"Array of chapters": "챕터 배열",
"Chapter title": "챕터 제목",
"Array of annotations": "주석 배열",
"Highlighted text": "하이라이트된 텍스트",
"Annotation note": "주석 노트",
"Date Format Tokens:": "날짜 형식 토큰:",
"Year (4 digits)": "연도 (4자리)",
"Month (01-12)": "월 (01-12)",
"Day (01-31)": "일 (01-31)",
"Hour (00-23)": "시 (00-23)",
"Minute (00-59)": "분 (00-59)",
"Second (00-59)": "초 (00-59)",
"Show Source": "소스 표시",
"No content to preview": "미리 볼 내용 없음",
"Export": "내보내기",
"Set Timeout": "시간 제한 설정",
"Select Voice": "음성 선택",
"Toggle Sticky Bottom TTS Bar": "고정 TTS 바 전환",
"Display what I'm reading on Discord": "Discord에 읽는 책 표시",
"Show on Discord": "Discord에 표시",
"Instant {{action}}": "즉시 {{action}}",
"Instant {{action}} Disabled": "즉시 {{action}} 비활성화",
"Annotation": "주석",
"Reset Template": "템플릿 초기화",
"Annotation style": "주석 스타일",
"Annotation color": "주석 색상",
"Annotation time": "주석 시간",
"AI": "AI",
"Are you sure you want to re-index this book?": "이 책을 다시 인덱싱하시겠습니까?",
"Enable AI in Settings": "설정에서 AI 활성화",
"Index This Book": "이 책 인덱싱",
"Enable AI search and chat for this book": "이 책에 대한 AI 검색 및 채팅 활성화",
"Start Indexing": "인덱싱 시작",
"Indexing book...": "책 인덱싱 중...",
"Preparing...": "준비 중...",
"Delete this conversation?": "이 대화를 삭제하시겠습니까?",
"No conversations yet": "아직 대화가 없습니다",
"Start a new chat to ask questions about this book": "이 책에 대해 질문하려면 새 채팅을 시작하세요",
"Rename": "이름 변경",
"New Chat": "새 채팅",
"Chat": "채팅",
"Please enter a model ID": "모델 ID를 입력하세요",
"Model not available or invalid": "모델을 사용할 수 없거나 유효하지 않습니다",
"Failed to validate model": "모델 검증 실패",
"Couldn't connect to Ollama. Is it running?": "Ollama에 연결할 수 없습니다. 실행 중인가요?",
"Invalid API key or connection failed": "API 키가 유효하지 않거나 연결 실패",
"Connection failed": "연결 실패",
"AI Assistant": "AI 어시스턴트",
"Enable AI Assistant": "AI 어시스턴트 활성화",
"Provider": "제공자",
"Ollama (Local)": "Ollama (로컬)",
"AI Gateway (Cloud)": "AI 게이트웨이 (클라우드)",
"Ollama Configuration": "Ollama 설정",
"Refresh Models": "모델 새로고침",
"AI Model": "AI 모델",
"No models detected": "모델이 감지되지 않았습니다",
"AI Gateway Configuration": "AI 게이트웨이 설정",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "고품질의 경제적인 AI 모델 중에서 선택하세요. 아래의 \"사용자 정의 모델\"을 선택하여 자신의 모델을 사용할 수도 있습니다.",
"API Key": "API 키",
"Get Key": "키 받기",
"Model": "모델",
"Custom Model...": "사용자 정의 모델...",
"Custom Model ID": "사용자 정의 모델 ID",
"Validate": "검증",
"Model available": "모델 사용 가능",
"Connection": "연결",
"Test Connection": "연결 테스트",
"Connected": "연결됨",
"Custom Colors": "사용자 정의 색상",
"Color E-Ink Mode": "컬러 E-Ink 모드",
"Reading Ruler": "읽기 자",
"Enable Reading Ruler": "읽기 자 활성화",
"Lines to Highlight": "강조할 줄 수",
"Ruler Color": "자 색상",
"Command Palette": "명령 팔레트",
"Search settings and actions...": "설정 및 작업 검색...",
"No results found for": "에 대한 결과를 찾을 수 없음",
"Type to search settings and actions": "입력하여 설정 및 작업 검색",
"Recent": "최근",
"navigate": "탐색",
"select": "선택",
"close": "닫기",
"Search Settings": "설정 검색",
"Page Margins": "페이지 여백",
"AI Provider": "AI 제공처",
"Ollama URL": "Ollama URL",
"Ollama Model": "Ollama 모델",
"AI Gateway Model": "AI 게이트웨이 모델",
"Actions": "작업",
"Navigation": "탐색",
"Set status for {{count}} book(s)_other": "책 {{count}}권 상태 설정",
"Mark as Unread": "읽지 않음으로 표시",
"Mark as Finished": "완료로 표시",
"Finished": "완료",
"Unread": "읽지 않음",
"Clear Status": "상태 지우기",
"Status": "상태",
"Loading": "로드 중...",
"Exit Paragraph Mode": "단락 모드 종료",
"Paragraph Mode": "단락 모드",
"Embedding Model": "임베딩 모델",
"{{count}} book(s) synced_other": "{{count}}권의 책이 동기화되었습니다",
"Unable to start RSVP": "RSVP를 시작할 수 없습니다",
"RSVP not supported for PDF": "PDF는 RSVP를 지원하지 않습니다",
"Select Chapter": "챕터 선택",
"Context": "문맥",
"Ready": "준비됨",
"Chapter Progress": "챕터 진행 상황",
"words": "단어",
"{{time}} left": "{{time}} 남음",
"Reading progress": "독서 진행 상황",
"Skip back 15 words": "15단어 뒤로",
"Back 15 words (Shift+Left)": "15단어 뒤로 (Shift+왼쪽 화살표)",
"Pause (Space)": "일시정지 (스페이스바)",
"Play (Space)": "재생 (스페이스바)",
"Skip forward 15 words": "15단어 앞으로",
"Forward 15 words (Shift+Right)": "15단어 앞으로 (Shift+오른쪽 화살표)",
"Decrease speed": "속도 줄이기",
"Slower (Left/Down)": "느리게 (왼쪽/아래 화살표)",
"Increase speed": "속도 높이기",
"Faster (Right/Up)": "빠르게 (오른쪽/위 화살표)",
"Start RSVP Reading": "RSVP 독서 시작",
"Choose where to start reading": "독서를 시작할 위치 선택",
"From Chapter Start": "챕터 시작부터",
"Start reading from the beginning of the chapter": "챕터 처음부터 다시 시작",
"Resume": "재개",
"Continue from where you left off": "중단한 지점부터 계속 읽기",
"From Current Page": "현재 페이지부터",
"Start from where you are currently reading": "현재 읽고 있는 위치부터 시작",
"From Selection": "선택 범위부터",
"Speed Reading Mode": "속독 모드",
"Scroll left": "왼쪽으로 스크롤",
"Scroll right": "오른쪽으로 스크롤",
"Library Sync Progress": "라이브러리 동기화 진행 상황",
"Back to library": "라이브러리로 돌아가기",
"Group by...": "그룹화 기준...",
"Export as Plain Text": "일반 텍스트로 내보내기",
"Export as Markdown": "Markdown으로 내보내기",
"Show Page Navigation Buttons": "탐색 버튼 표시",
"Page {{number}}": "{{number}} 페이지",
"highlight": "하이라이트",
"underline": "밑줄",
"squiggly": "구불구불한 선",
"red": "빨간색",
"violet": "보라색",
"blue": "파란색",
"green": "초록색",
"yellow": "노란색",
"Select {{style}} style": "{{style}} 스타일 선택",
"Select {{color}} color": "{{color}} 색상 선택",
"Close Book": "책 닫기",
"Speed Reading": "속독",
"Close Speed Reading": "속독 닫기",
"Authors": "저자",
"Books": "도서",
"Groups": "그룹",
"Back to TTS Location": "TTS 위치로 돌아가기",
"Metadata": "메타데이터",
"Image viewer": "이미지 뷰어",
"Previous Image": "이전 이미지",
"Next Image": "다음 이미지",
"Zoomed": "확대됨",
"Zoom level": "확대 수준",
"Table viewer": "테이블 뷰어",
"Unable to connect to Readwise. Please check your network connection.": "Readwise에 연결할 수 없습니다. 네트워크 연결을 확인해 주세요.",
"Invalid Readwise access token": "유효하지 않은 Readwise 액세스 토큰입니다",
"Disconnected from Readwise": "Readwise와 연결이 끊어졌습니다",
"Never": "안 함",
"Readwise Settings": "Readwise 설정",
"Connected to Readwise": "Readwise에 연결됨",
"Last synced: {{time}}": "마지막 동기화: {{time}}",
"Sync Enabled": "동기화 활성화됨",
"Disconnect": "연결 해제",
"Connect your Readwise account to sync highlights.": "하이라이트를 동기화하려면 Readwise 계정렬 연결하세요.",
"Get your access token at": "액세스 토큰 받기:",
"Access Token": "액세스 토큰",
"Paste your Readwise access token": "Readwise 액세스 토큰을 붙여넣으세요",
"Config": "구성",
"Readwise Sync": "Readwise 동기화",
"Push Highlights": "하이라이트 푸시",
"Highlights synced to Readwise": "하이라이트가 Readwise에 동기화되었습니다",
"Readwise sync failed: no internet connection": "Readwise 동기화 실패: 인터넷 연결 없음",
"Readwise sync failed: {{error}}": "Readwise 동기화 실패: {{error}}",
"System Screen Brightness": "시스템 화면 밝기",
"Page:": "페이지:",
"Page: {{number}}": "페이지: {{number}}",
"Annotation page number": "주석 페이지 번호",
"Translating...": "번역 중...",
"Show Battery Percentage": "배터리 백분율 표시",
"Hide Scrollbar": "스크롤바 숨기기",
"Skip to last reading position": "마지막 읽기 위치로 이동",
"Show context": "맥락 표시",
"Hide context": "맥락 숨기기",
"Decrease font size": "글꼴 크기 줄이기",
"Increase font size": "글꼴 크기 늘리기",
"Focus": "초점",
"Theme color": "테마 색상",
"Import failed": "가져오기 실패",
"Available Formatters:": "사용 가능한 포맷터:",
"Format date": "날짜 형식",
"Markdown block quote (> per line)": "Markdown 인용 블록 (줄마다 >)",
"Newlines to <br>": "줄바꿈을 <br>로 변환",
"Change case": "대소문자 변경",
"Trim whitespace": "공백 제거",
"Truncate to n characters": "n자로 자르기",
"Replace text": "텍스트 바꾸기",
"Fallback value": "기본값",
"Get length": "길이 가져오기",
"First/last element": "첫 번째/마지막 요소",
"Join array": "배열 합치기",
"Backup failed: {{error}}": "백업 실패: {{error}}",
"Select Backup": "백업 선택",
"Restore failed: {{error}}": "복원 실패: {{error}}",
"Backup & Restore": "백업 및 복원",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "라이브러리를 백업하거나 이전 백업에서 복원하세요. 복원 시 현재 라이브러리와 병합됩니다.",
"Backup Library": "라이브러리 백업",
"Restore Library": "라이브러리 복원",
"Creating backup...": "백업 생성 중...",
"Restoring library...": "라이브러리 복원 중...",
"{{current}} of {{total}} items": "{{current}} / {{total}} 항목",
"Backup completed successfully!": "백업이 완료되었습니다!",
"Restore completed successfully!": "복원이 완료되었습니다!",
"Your library has been saved to the selected location.": "라이브러리가 선택한 위치에 저장되었습니다.",
"{{added}} books added, {{updated}} books updated.": "{{added}}권 추가, {{updated}}권 업데이트되었습니다.",
"Operation failed": "작업 실패",
"Loading library...": "라이브러리 로딩 중...",
"{{count}} books refreshed_other": "{{count}}권 새로고침됨",
"Failed to refresh metadata": "메타데이터 새로고침 실패",
"Refresh Metadata": "메타데이터 새로고침",
"Keyboard Shortcuts": "키보드 단축키",
"View all keyboard shortcuts": "모든 키보드 단축키 보기",
"Switch Sidebar Tab": "사이드바 탭 전환",
"Toggle Notebook": "노트북 표시/숨기기",
"Search in Book": "책에서 검색",
"Toggle Scroll Mode": "스크롤 모드 전환",
"Toggle Select Mode": "선택 모드 전환",
"Toggle Bookmark": "북마크 전환",
"Toggle Text to Speech": "텍스트 음성 변환 전환",
"Play / Pause TTS": "TTS 재생 / 일시정지",
"Toggle Paragraph Mode": "문단 모드 전환",
"Highlight Selection": "선택 영역 강조",
"Underline Selection": "선택 영역 밑줄",
"Annotate Selection": "선택 영역 주석",
"Search Selection": "선택 영역 검색",
"Copy Selection": "선택 영역 복사",
"Translate Selection": "선택 영역 번역",
"Dictionary Lookup": "사전 검색",
"Wikipedia Lookup": "위키백과 검색",
"Read Aloud Selection": "선택 영역 소리 내어 읽기",
"Proofread Selection": "선택 영역 교정",
"Open Settings": "설정 열기",
"Open Command Palette": "명령 팔레트 열기",
"Show Keyboard Shortcuts": "키보드 단축키 표시",
"Open Books": "책 열기",
"Toggle Fullscreen": "전체 화면 전환",
"Close Window": "창 닫기",
"Quit App": "앱 종료",
"Go Left / Previous Page": "왼쪽으로 / 이전 페이지",
"Go Right / Next Page": "오른쪽으로 / 다음 페이지",
"Go Up": "위로",
"Go Down": "아래로",
"Previous Chapter": "이전 장",
"Next Chapter": "다음 장",
"Scroll Half Page Down": "반 페이지 아래로 스크롤",
"Scroll Half Page Up": "반 페이지 위로 스크롤",
"Save Note": "메모 저장",
"Single Section Scroll": "단일 섹션 스크롤",
"General": "일반",
"Text to Speech": "텍스트 음성 변환",
"Zoom": "확대/축소",
"Window": "창",
"Your Bookshelf": "내 책장",
"TTS": "음성 읽기",
"Media Info": "미디어 정보",
"Update Frequency": "업데이트 빈도",
"Every Sentence": "문장마다",
"Every Paragraph": "단락마다",
"Every Chapter": "챕터마다",
"TTS Media Info Update Frequency": "TTS 미디어 정보 업데이트 빈도",
"Select reading speed": "읽기 속도 선택",
"Drag to seek": "드래그하여 탐색",
"Punctuation Delay": "구두점 지연",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "계속하기 전에 이 OPDS 연결이 웹 앱의 Readest 서버를 통해 프록시될 것임을 확인해 주세요.",
"Custom Headers": "사용자 정의 헤더",
"Custom Headers (optional)": "사용자 정의 헤더 (선택 사항)",
"Add one header per line using \"Header-Name: value\".": "\"Header-Name: value\" 형식으로 한 줄에 하나의 헤더를 추가하세요.",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "이 OPDS 연결이 웹 앱의 Readest 서버를 통해 프록시될 것임을 이해합니다. 이 자격 증명이나 헤더에 대해 Readest를 신뢰하지 않는다면 네이티브 앱을 사용해야 합니다.",
"Unable to connect to Hardcover. Please check your network connection.": "Hardcover에 연결할 수 없습니다. 네트워크 연결을 확인해 주세요.",
"Invalid Hardcover API token": "유효하지 않은 Hardcover API 토큰",
"Disconnected from Hardcover": "Hardcover에서 연결 해제됨",
"Hardcover Settings": "Hardcover 설정",
"Connected to Hardcover": "Hardcover에 연결됨",
"Connect your Hardcover account to sync reading progress and notes.": "독서 진행 상황과 메모를 동기화하려면 Hardcover 계정을 연결하세요.",
"Get your API token from hardcover.app → Settings → API.": "hardcover.app → 설정 → API에서 API 토큰을 받으세요.",
"API Token": "API 토큰",
"Paste your Hardcover API token": "Hardcover API 토큰을 붙여넣기",
"Hardcover sync enabled for this book": "이 책의 Hardcover 동기화가 활성화됨",
"Hardcover sync disabled for this book": "이 책의 Hardcover 동기화가 비활성화됨",
"Hardcover Sync": "Hardcover 동기화",
"Enable for This Book": "이 책에 대해 활성화",
"Push Notes": "메모 보내기",
"Enable Hardcover sync for this book first.": "먼저 이 책의 Hardcover 동기화를 활성화하세요.",
"No annotations or excerpts to sync for this book.": "이 책에 동기화할 주석이나 발췌가 없습니다.",
"Configure Hardcover in Settings first.": "먼저 설정에서 Hardcover를 구성하세요.",
"No new Hardcover note changes to sync.": "동기화할 새로운 Hardcover 메모 변경 사항이 없습니다.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover 동기화 완료: {{inserted}}개 추가, {{updated}}개 업데이트, {{skipped}}개 변경 없음",
"Hardcover notes sync failed: {{error}}": "Hardcover 메모 동기화 실패: {{error}}",
"Reading progress synced to Hardcover": "독서 진행 상황이 Hardcover에 동기화됨",
"Hardcover progress sync failed: {{error}}": "Hardcover 진행 상황 동기화 실패: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "기존 소스 식별자 유지",
"Toggle Toolbar": "도구 모음 전환"
}
File diff suppressed because it is too large Load Diff
@@ -23,9 +23,6 @@
"Token": "Token",
"Your OTP token": "Uw OTP-token",
"Verify token": "Token verifiëren",
"Sign in with Google": "Inloggen met Google",
"Sign in with Apple": "Inloggen met Apple",
"Sign in with GitHub": "Inloggen met GitHub",
"New Password": "Nieuw wachtwoord",
"Your new password": "Uw nieuwe wachtwoord",
"Update password": "Wachtwoord bijwerken",
@@ -55,7 +52,6 @@
"Search Books...": "Boeken zoeken...",
"Clear Search": "Zoekopdracht wissen",
"Import Books": "Boeken importeren",
"Select Multiple Books": "Meerdere boeken selecteren",
"Select Books": "Boeken selecteren",
"Logged in as {{userDisplayName}}": "Ingelogd als {{userDisplayName}}",
"Logged in": "Ingelogd",
@@ -82,9 +78,9 @@
"Descending": "Aflopend",
"Sort by...": "Sorteren op...",
"No supported files found. Supported formats: {{formats}}": "Geen ondersteunde bestanden gevonden. Ondersteunde formaten: {{formats}}",
"No chapters detected.": "Geen hoofdstukken gedetecteerd.",
"Failed to parse the EPUB file.": "EPUB-bestand kon niet worden verwerkt.",
"This book format is not supported.": "Dit boekformaat wordt niet ondersteund.",
"No chapters detected": "Geen hoofdstukken gedetecteerd",
"Failed to parse the EPUB file": "EPUB-bestand kon niet worden verwerkt",
"This book format is not supported": "Dit boekformaat wordt niet ondersteund",
"Failed to import book(s): {{filenames}}": "Importeren van boek(en) mislukt: {{filenames}}",
"Book uploaded: {{title}}": "Boek geüpload: {{title}}",
"Insufficient storage quota": "Onvoldoende opslagruimte",
@@ -183,10 +179,7 @@
"Portrait": "Portret",
"Landscape": "Landschap",
"Behavior": "Gedrag",
"Continuous Scroll": "Doorlopend scrollen",
"Volume Keys for Page Flip": "Volumetoetsen voor pagina omslaan",
"Clicks for Page Flip": "Klikken voor pagina omslaan",
"Swap Clicks Area": "Klikgebieden omwisselen",
"Apply": "Toepassen",
"Font": "Lettertype",
"Layout": "Opmaak",
@@ -199,7 +192,6 @@
"Link Color": "Linkkleur",
"Preview": "Voorbeeld",
"Font & Layout": "Lettertype & opmaak",
"Book Cover": "Boekomslag",
"More Info": "Meer informatie",
"Parallel Read": "Parallel lezen",
"Export Annotations": "Annotaties exporteren",
@@ -211,9 +203,8 @@
"Match Whole Words": "Hele woorden",
"Match Diacritics": "Diakritische tekens",
"TOC": "Inhoudsopgave",
"Table of Contents": "Inhoudsopgave",
"Sidebar": "Zijbalk",
"TTS not supported for PDF": "TTS niet ondersteund voor PDF",
"TTS not supported in this device": "TTS niet ondersteund op dit apparaat",
"No Timeout": "Geen time-out",
"{{value}} minute": "{{value}} minuut",
"{{value}} minutes": "{{value}} minuten",
@@ -238,15 +229,13 @@
"Error checking for updates": "Fout bij controleren op updates",
"Book Details": "Boekdetails",
"Unknown": "Onbekend",
"Publisher:": "Uitgever:",
"Published:": "Gepubliceerd:",
"Updated:": "Bijgewerkt:",
"Added:": "Toegevoegd:",
"Language:": "Taal:",
"Subjects:": "Onderwerpen:",
"Format:": "Formaat:",
"File Size:": "Bestandsgrootte:",
"Description:": "Beschrijving:",
"Publisher": "Uitgever",
"Published": "Gepubliceerd",
"Updated": "Bijgewerkt",
"Added": "Toegevoegd",
"Subjects": "Onderwerpen",
"File Size": "Bestandsgrootte",
"Description": "Beschrijving",
"No description available": "Geen beschrijving beschikbaar",
"Drop to Import Books": "Sleep om boeken te importeren",
"A new version of Readest is available!": "Een nieuwe versie van Readest is beschikbaar!",
@@ -255,7 +244,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "Downloaden {{downloaded}} van {{contentLength}}",
"Download finished": "Download voltooid",
"DOWNLOAD & INSTALL": "DOWNLOADEN & INSTALLEREN",
"Changelog:": "Wijzigingslogboek:",
"Changelog": "Wijzigingslogboek",
"Software Update": "Software-update",
"LXGW WenKai GB Screen": "LXGW WenKai GB Scherm",
"LXGW WenKai TC": "LXGW WenKai TC",
@@ -274,7 +263,7 @@
"Reveal in File Explorer": "Tonen in Verkenner",
"Reveal in Folder": "Tonen in map",
"Don't have an account? Sign up": "Nog geen account? Registreer u",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "De hele wereld is een toneel,\nEn alle mannen en vrouwen slechts spelers;\nZij hebben hun uitgangen en hun entrees,\nEn één man speelt in zijn tijd vele rollen,\nZijn daden zijnde zeven leeftijden.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "De hele wereld is een toneel,\nEn alle mannen en vrouwen slechts spelers;\nZij hebben hun uitgangen en hun entrees,\nEn één man speelt in zijn tijd vele rollen,\nZijn daden zijnde zeven leeftijden.\n\n— William Shakespeare",
"Next Section": "Volgende sectie",
"Previous Section": "Vorige sectie",
"Next Page": "Volgende pagina",
@@ -300,12 +289,11 @@
"Disable Translation": "Vertaling uitschakelen",
"Scroll": "Scrollen",
"Overlap Pixels": "Overlap pixels",
"Click": "Klik",
"System Language": "Systemtaal",
"Security": "Beveiliging",
"Allow JavaScript": "JavaScript toestaan",
"Enable only if you trust the file.": "Schakel alleen in als u het bestand vertrouwt.",
"Sort TOC by Page": "__STRING_NOT_TRANSLATED__",
"Sort TOC by Page": "TOC sorteren op pagina",
"Search in {{count}} Book(s)..._one": "Zoeken in {{count}} Boek...",
"Search in {{count}} Book(s)..._other": "Zoeken in {{count}} Boeken...",
"No notes match your search": "Geen notities gevonden",
@@ -314,7 +302,6 @@
"Synced at {{time}}": "Gesynchroniseerd om {{time}}",
"Never synced": "Nooit gesynchroniseerd",
"Show Remaining Time": "Toon resterende tijd",
"Show Page Number": "Toon paginanummer",
"{{time}} min left in chapter": "Nog {{time}} min in hoofdstuk",
"Override Book Color": "Boekkleur overschrijven",
"Login Required": "Inloggen vereist",
@@ -337,7 +324,6 @@
"Left Margin (px)": "Linker marge (px)",
"Column Gap (%)": "Kolomafstand (%)",
"Always Show Status Bar": "Statusbalk altijd weergeven",
"Translation Not Available": "Vertaling niet beschikbaar",
"Custom Content CSS": "Aangepaste inhoud-CSS",
"Enter CSS for book content styling...": "Voer CSS in voor de opmaak van de boekinhoud...",
"Custom Reader UI CSS": "Aangepaste interface-CSS",
@@ -347,11 +333,11 @@
"Fit": "Passend maken",
"Reset {{settings}}": "Reset {{settings}}",
"Reset Settings": "Instellingen resetten",
"{{count}} pages left in chapter_one": "Nog {{count}} pagina in hoofdstuk",
"{{count}} pages left in chapter_other": "Nog {{count}} paginas in hoofdstuk",
"{{count}} pages left in chapter_one": "<1>Nog </1><0>{{count}}</0><1> pagina in hoofdstuk</1>",
"{{count}} pages left in chapter_other": "<1>Nog </1><0>{{count}}</0><1> paginas in hoofdstuk</1>",
"Show Remaining Pages": "Toon resterende paginas",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Abonnement beheren",
"Coming Soon": "Binnenkort beschikbaar",
@@ -359,7 +345,6 @@
"Upgrade to Plus or Pro": "Upgrade naar Plus of Pro",
"Current Plan": "Huidig abonnement",
"Plan Limits": "Abonnementslimieten",
"Failed to manage subscription. Please try again later.": "Abonnement beheren is mislukt. Probeer het later opnieuw.",
"Processing your payment...": "Je betaling wordt verwerkt...",
"Please wait while we confirm your subscription.": "Even geduld terwijl we je abonnement bevestigen.",
"Payment Processing": "Betaling verwerken",
@@ -370,7 +355,6 @@
"Email:": "E-mail:",
"Plan:": "Abonnement:",
"Amount:": "Bedrag:",
"Subscription ID:": "Abonnements-ID:",
"Go to Library": "Ga naar bibliotheek",
"Need help? Contact our support team at support@readest.com": "Hulp nodig? Neem contact op met support via support@readest.com",
"Free Plan": "Gratis abonnement",
@@ -402,7 +386,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "Luister zonder limieten—zet zoveel tekst als je wilt om in meeslepende audio.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Ontsluit verbeterde vertaalfuncties met meer dagelijks gebruik en geavanceerde opties.",
"DeepL Pro Access": "DeepL Pro Toegang",
"2 GB Cloud Sync Storage": "2 GB Cloud Sync Opslag",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Geniet van snellere reacties en toegewijde hulp wanneer je hulp nodig hebt.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Dagelijks vertaalquotum bereikt. Upgrade je abonnement om AI vertalingen te blijven gebruiken.",
"Includes All Plus Plan Benefits": "Inclusief Alle Plus Plan Voordelen",
@@ -412,10 +395,793 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Benut krachtige AI tools voor slimmer lezen, vertalen en content ontdekking.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Vertaal dagelijks tot 100.000 tekens met de meest nauwkeurige vertaalengine.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Vertaal dagelijks tot 500.000 tekens met de meest nauwkeurige vertaalengine.",
"10 GB Cloud Sync Storage": "10 GB Cloud Sync Opslag",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "Sla je hele leesverzameling veilig op en benader deze met tot 2 GB cloudopslag.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "Sla je hele leesverzameling veilig op en benader deze met tot 10 GB cloudopslag.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Sla je hele leesverzameling veilig op en benader deze met tot 5 GB cloudopslag.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Sla je hele leesverzameling veilig op en benader deze met tot 20 GB cloudopslag.",
"Deleted cloud backup of the book: {{title}}": "Verwijderde cloudback-up van het boek: {{title}}",
"Failed to delete cloud backup of the book": "Verwijderen van cloudback-up van het boek is mislukt.",
"Are you sure to delete the cloud backup of the selected book?": "Weet je zeker dat je de cloudback-up van het geselecteerde boek wilt verwijderen?"
"Are you sure to delete the cloud backup of the selected book?": "Weet je zeker dat je de cloudback-up van het geselecteerde boek wilt verwijderen?",
"What's New in Readest": "Wat is er nieuw in Readest",
"Enter book title": "Voer boektitel in",
"Subtitle": "Ondertitel",
"Enter book subtitle": "Voer boek ondertitel in",
"Enter author name": "Voer auteursnaam in",
"Series": "Serie",
"Enter series name": "Voer serienaam in",
"Series Index": "Serie nummer",
"Enter series index": "Voer serie nummer in",
"Total in Series": "Totaal in serie",
"Enter total books in series": "Voer totaal aantal boeken in serie in",
"Enter publisher": "Voer uitgever in",
"Publication Date": "Publicatiedatum",
"Identifier": "Identificatie",
"Enter book description": "Voer boekbeschrijving in",
"Change cover image": "Wijzig omslagafbeelding",
"Replace": "Vervangen",
"Unlock cover": "Omslag ontgrendelen",
"Lock cover": "Omslag vergrendelen",
"Auto-Retrieve Metadata": "Metadata automatisch ophalen",
"Auto-Retrieve": "Automatisch ophalen",
"Unlock all fields": "Alle velden ontgrendelen",
"Unlock All": "Alles ontgrendelen",
"Lock all fields": "Alle velden vergrendelen",
"Lock All": "Alles vergrendelen",
"Reset": "Herstellen",
"Edit Metadata": "Metadata bewerken",
"Locked": "Vergrendeld",
"Select Metadata Source": "Selecteer metadata bron",
"Keep manual input": "Handmatige invoer behouden",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Fictie, Wetenschap, Geschiedenis",
"Open Book in New Window": "Open boek in nieuw venster",
"Voices for {{lang}}": "Stemmen voor {{lang}}",
"Yandex Translate": "Yandex Vertalen",
"YYYY or YYYY-MM-DD": "YYYY of YYYY-MM-DD",
"Restore Purchase": "Herstel aankoop",
"No purchases found to restore.": "Geen aankopen gevonden om te herstellen.",
"Failed to restore purchases.": "Herstellen van aankopen is mislukt.",
"Failed to manage subscription.": "Beheren van abonnement is mislukt.",
"Failed to load subscription plans.": "Laden van abonnement plannen is mislukt.",
"year": "jaar",
"Failed to create checkout session": "Kon de afreken sessie niet aanmaken",
"Storage": "Opslag",
"Terms of Service": "Gebruiksvoorwaarden",
"Privacy Policy": "Privacybeleid",
"Disable Double Click": "Dubbelklikken uitschakelen",
"TTS not supported for this document": "TTS niet ondersteund voor dit document",
"Reset Password": "Wachtwoord resetten",
"Show Reading Progress": "Leesvoortgang weergeven",
"Reading Progress Style": "Stijl van leesvoortgang",
"Page Number": "Pagina nummer",
"Percentage": "Percentage",
"Deleted local copy of the book: {{title}}": "Verwijderde lokale kopie van het boek: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Verwijderen van cloudback-up van het boek is mislukt: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Verwijderen van lokale kopie van het boek is mislukt: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Weet je zeker dat je de lokale kopie van het geselecteerde boek wilt verwijderen?",
"Remove from Cloud & Device": "Verwijder uit Cloud & Apparaat",
"Remove from Cloud Only": "Verwijder alleen uit Cloud",
"Remove from Device Only": "Verwijder alleen uit Apparaat",
"Disconnected": "Verbroken",
"KOReader Sync Settings": "KOReader Sync-instellingen",
"Sync Strategy": "Synchronisatiestrategie",
"Ask on conflict": "Vraag bij conflict",
"Always use latest": "Altijd de nieuwste gebruiken",
"Send changes only": "Verzend alleen wijzigingen",
"Receive changes only": "Ontvang alleen wijzigingen",
"Checksum Method": "Checksum-methode",
"File Content (recommended)": "Bestandsinhoud (aanbevolen)",
"File Name": "Bestandsnaam",
"Device Name": "Apparaatnaam",
"Connect to your KOReader Sync server.": "Verbind met je KOReader Sync-server.",
"Server URL": "Server-URL",
"Username": "Gebruikersnaam",
"Your Username": "Je gebruikersnaam",
"Password": "Wachtwoord",
"Connect": "Verbinden",
"KOReader Sync": "KOReader Sync",
"Sync Conflict": "Synchronisatieconflict",
"Sync reading progress from \"{{deviceName}}\"?": "Leesvoortgang synchroniseren van \"{{deviceName}}\"?",
"another device": "een ander apparaat",
"Local Progress": "Lokale voortgang",
"Remote Progress": "Externe voortgang",
"Page {{page}} of {{total}} ({{percentage}}%)": "Pagina {{page}} van {{total}} ({{percentage}}%)",
"Current position": "Huidige positie",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Ongeveer pagina {{page}} van {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Ongeveer {{percentage}}%",
"Failed to connect": "Verbinding mislukt",
"Sync Server Connected": "Synchronisatie server verbonden",
"Sync as {{userDisplayName}}": "Synchroniseren als {{userDisplayName}}",
"Custom Fonts": "Aangepaste Lettertypen",
"Cancel Delete": "Verwijderen Annuleren",
"Import Font": "Lettertype Importeren",
"Delete Font": "Lettertype Verwijderen",
"Tips": "Tips",
"Custom fonts can be selected from the Font Face menu": "Aangepaste lettertypen kunnen worden geselecteerd vanuit het Lettertype menu",
"Manage Custom Fonts": "Aangepaste Lettertypen Beheren",
"Select Files": "Bestanden Selecteren",
"Select Image": "Afbeelding Selecteren",
"Select Video": "Video Selecteren",
"Select Audio": "Audio Selecteren",
"Select Fonts": "Lettertypen Selecteren",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Ondersteunde lettertypeformaten: .ttf, .otf, .woff, .woff2",
"Push Progress": "Voortgang pushen",
"Pull Progress": "Voortgang pullen",
"Previous Paragraph": "Vorige alinea",
"Previous Sentence": "Vorige zin",
"Pause": "Pauzeren",
"Play": "Afspelen",
"Next Sentence": "Volgende zin",
"Next Paragraph": "Volgende alinea",
"Separate Cover Page": "Afzonderlijke omslagpagina",
"Resize Notebook": "Formaat Notitieblok Aanpassen",
"Resize Sidebar": "Formaat Zijbalk Aanpassen",
"Get Help from the Readest Community": "Hulp krijgen van de Readest Community",
"Remove cover image": "Omslagafbeelding verwijderen",
"Bookshelf": "Boekenkast",
"View Menu": "Menu bekijken",
"Settings Menu": "Instellingenmenu",
"View account details and quota": "Accountgegevens en quotum bekijken",
"Library Header": "Bibliotheekkop",
"Book Content": "Boekinhoud",
"Footer Bar": "Voettekstbalk",
"Header Bar": "Koptekstbalk",
"View Options": "Weergaveopties",
"Book Menu": "Boekmenu",
"Search Options": "Zoekopties",
"Close": "Sluiten",
"Delete Book Options": "Boekverwijderopties",
"ON": "AAN",
"OFF": "UIT",
"Reading Progress": "Leesvoortgang",
"Page Margin": "Pagina Marges",
"Remove Bookmark": "Bladwijzer Verwijderen",
"Add Bookmark": "Bladwijzer Toevoegen",
"Books Content": "Boekinhoud",
"Jump to Location": "Ga naar Locatie",
"Unpin Notebook": "Notitieblok Losmaken",
"Pin Notebook": "Notitieblok Vastmaken",
"Hide Search Bar": "Verberg Zoekbalk",
"Show Search Bar": "Toon Zoekbalk",
"On {{current}} of {{total}} page": "Op {{current}} van {{total}} pagina",
"Section Title": "Sectietitel",
"Decrease": "Verkleinen",
"Increase": "Vergroten",
"Settings Panels": "Instellingenpanelen",
"Settings": "Instellingen",
"Unpin Sidebar": "Zijbalk Losmaken",
"Pin Sidebar": "Zijbalk Vastmaken",
"Toggle Sidebar": "Zijbalk Wisselen",
"Toggle Translation": "Vertaling Wisselen",
"Translation Disabled": "Vertaling Uitgeschakeld",
"Minimize": "Minimaliseren",
"Maximize or Restore": "Maximaliseren of Herstellen",
"Exit Parallel Read": "Parallel Lezen Afsluiten",
"Enter Parallel Read": "Parallel Lezen Starten",
"Zoom Level": "Zoomniveau",
"Zoom Out": "Zoom Verkleinen",
"Reset Zoom": "Zoom Reset",
"Zoom In": "Zoom Vergroten",
"Zoom Mode": "Zoom Modus",
"Single Page": "Enkele Pagina",
"Auto Spread": "Automatische Verspreiding",
"Fit Page": "Pagina Aanpassen",
"Fit Width": "Breedte Aanpassen",
"Failed to select directory": "Selecteren van map is mislukt",
"The new data directory must be different from the current one.": "De nieuwe gegevensmap moet anders zijn dan de huidige.",
"Migration failed: {{error}}": "Migratie mislukt: {{error}}",
"Change Data Location": "Gegevenslocatie Wijzigen",
"Current Data Location": "Huidige Gegevenslocatie",
"Total size: {{size}}": "Totale grootte: {{size}}",
"Calculating file info...": "Bestandinformatie wordt berekend...",
"New Data Location": "Nieuwe Gegevenslocatie",
"Choose Different Folder": "Kies Een Andere Map",
"Choose New Folder": "Kies Nieuwe Map",
"Migrating data...": "Gegevens worden gemigreerd...",
"Copying: {{file}}": "Kopiëren: {{file}}",
"{{current}} of {{total}} files": "{{current}} van {{total}} bestanden",
"Migration completed successfully!": "Migratie succesvol voltooid!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Uw gegevens zijn naar de nieuwe locatie verplaatst. Start de applicatie opnieuw op om het proces te voltooien.",
"Migration failed": "Migratie mislukt",
"Important Notice": "Belangrijke Kennisgeving",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Dit zal al uw app-gegevens naar de nieuwe locatie verplaatsen. Zorg ervoor dat de bestemming voldoende vrije ruimte heeft.",
"Restart App": "Herstart App",
"Start Migration": "Start Migratie",
"Advanced Settings": "Geavanceerde Instellingen",
"File count: {{size}}": "Bestandsaantal: {{size}}",
"Background Read Aloud": "Achtergrond Voorlezen",
"Ready to read aloud": "Klaar om voor te lezen",
"Read Aloud": "Voorlezen",
"Screen Brightness": "Schermhelderheid",
"Background Image": "Achtergrondafbeelding",
"Import Image": "Afbeelding importeren",
"Opacity": "Doorzichtigheid",
"Size": "Grootte",
"Cover": "Omslag",
"Contain": "Bevatten",
"{{number}} pages left in chapter": "<1>Nog </1><0>{{number}}</0><1> paginas in hoofdstuk</1>",
"Device": "Apparaat",
"E-Ink Mode": "E-Ink Modus",
"Highlight Colors": "Markeerkleuren",
"Pagination": "Paginering",
"Disable Double Tap": "Schakel Dubbel Tikken Uit",
"Tap to Paginate": "Tik om te Pagineren",
"Click to Paginate": "Klik om te Pagineren",
"Tap Both Sides": "Tik op Beide Zijden",
"Click Both Sides": "Klik op Beide Zijden",
"Swap Tap Sides": "Wissel Tap Zijden",
"Swap Click Sides": "Wissel Klik Zijden",
"Source and Translated": "Bron en Vertaling",
"Translated Only": "Alleen Vertaling",
"Source Only": "Alleen Bron",
"TTS Text": "TTS Tekst",
"The book file is corrupted": "Het boekbestand is beschadigd",
"The book file is empty": "Het boekbestand is leeg",
"Failed to open the book file": "Het openen van het boekbestand is mislukt",
"On-Demand Purchase": "On-Demand Aankoop",
"Full Customization": "Volledige Aanpassing",
"Lifetime Plan": "Levenslange Abonnement",
"One-Time Payment": "Eenmalige Betaling",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Doe een eenmalige betaling om levenslange toegang te krijgen tot specifieke functies op alle apparaten. Koop specifieke functies of diensten alleen wanneer je ze nodig hebt.",
"Expand Cloud Sync Storage": "Cloud Sync Opslag Uitbreiden",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Breid je cloudopslag voor altijd uit met een eenmalige aankoop. Elke extra aankoop voegt meer ruimte toe.",
"Unlock All Customization Options": "Ontgrendel Alle Aanpassingsopties",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Ontgrendel extra thema's, lettertypen, lay-outopties en voorlezen, vertalers, cloudopslagdiensten.",
"Purchase Successful!": "Aankoop Succesvol!",
"lifetime": "levenslang",
"Thank you for your purchase! Your payment has been processed successfully.": "Bedankt voor je aankoop! Je betaling is succesvol verwerkt.",
"Order ID:": "Bestel-ID:",
"TTS Highlighting": "TTS-markering",
"Style": "Stijl",
"Underline": "Onderstrepen",
"Strikethrough": "Doorhalen",
"Squiggly": "Kronkelig",
"Outline": "Omtrek",
"Save Current Color": "Huidige kleur opslaan",
"Quick Colors": "Snelle kleuren",
"Highlighter": "Marker",
"Save Book Cover": "Opslaan boekomslag",
"Auto-save last book cover": "Automatisch opslaan laatste boekomslag",
"Back": "Terug",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Bevestigingsmail verzonden! Controleer je oude en nieuwe e-mailadres om de wijziging te bevestigen.",
"Failed to update email": "E-mail bijwerken mislukt",
"New Email": "Nieuw e-mailadres",
"Your new email": "Je nieuwe e-mailadres",
"Updating email ...": "E-mail wordt bijgewerkt...",
"Update email": "E-mail bijwerken",
"Current email": "Huidig e-mailadres",
"Update Email": "E-mail bijwerken",
"All": "Alles",
"Unable to open book": "Kan boek niet openen",
"Punctuation": "Interpunctie",
"Replace Quotation Marks": "Aanhalingstekens vervangen",
"Enabled only in vertical layout.": "Alleen ingeschakeld in verticale lay-out.",
"No Conversion": "Geen conversie",
"Simplified to Traditional": "Vereenvoudigd → Traditioneel",
"Traditional to Simplified": "Traditioneel → Vereenvoudigd",
"Simplified to Traditional (Taiwan)": "Vereenvoudigd → Traditioneel (Taiwan)",
"Simplified to Traditional (Hong Kong)": "Vereenvoudigd → Traditioneel (Hong Kong)",
"Simplified to Traditional (Taiwan), with phrases": "Vereenvoudigd → Traditioneel (Taiwan • zinnen)",
"Traditional (Taiwan) to Simplified": "Traditioneel (Taiwan) → Vereenvoudigd",
"Traditional (Hong Kong) to Simplified": "Traditioneel (Hong Kong) → Vereenvoudigd",
"Traditional (Taiwan) to Simplified, with phrases": "Traditioneel (Taiwan • zinnen) → Vereenvoudigd",
"Convert Simplified and Traditional Chinese": "Converteer Vereenvoudigd/Traditioneel Chinees",
"Convert Mode": "Conversiemodus",
"Failed to auto-save book cover for lock screen: {{error}}": "Automatisch opslaan van boekomslag voor vergrendelscherm mislukt: {{error}}",
"Download from Cloud": "Downloaden van Cloud",
"Upload to Cloud": "Uploaden naar Cloud",
"Clear Custom Fonts": "Aangepaste Lettertypen Wissen",
"Columns": "Kolommen",
"OPDS Catalogs": "OPDS-catalogi",
"Adding LAN addresses is not supported in the web app version.": "Het toevoegen van LAN-adressen wordt niet ondersteund in de webversie.",
"Invalid OPDS catalog. Please check the URL.": "Ongeldige OPDS-catalogus. Controleer de URL.",
"Browse and download books from online catalogs": "Blader door en download boeken uit online catalogi",
"My Catalogs": "Mijn catalogi",
"Add Catalog": "Catalogus toevoegen",
"No catalogs yet": "Nog geen catalogi",
"Add your first OPDS catalog to start browsing books": "Voeg je eerste OPDS-catalogus toe om boeken te bekijken",
"Add Your First Catalog": "Voeg je eerste catalogus toe",
"Browse": "Bladeren",
"Popular Catalogs": "Populaire catalogi",
"Add": "Toevoegen",
"Add OPDS Catalog": "OPDS-catalogus toevoegen",
"Catalog Name": "Catalogusnaam",
"My Calibre Library": "Mijn Calibre-bibliotheek",
"OPDS URL": "OPDS-URL",
"Username (optional)": "Gebruikersnaam (optioneel)",
"Password (optional)": "Wachtwoord (optioneel)",
"Description (optional)": "Beschrijving (optioneel)",
"A brief description of this catalog": "Een korte beschrijving van deze catalogus",
"Validating...": "Valideren...",
"View All": "Alles bekijken",
"Forward": "Verder",
"Home": "Startpagina",
"{{count}} items_one": "{{count}} item",
"{{count}} items_other": "{{count}} items",
"Download completed": "Download voltooid",
"Download failed": "Download mislukt",
"Open Access": "Open toegang",
"Borrow": "Lenen",
"Buy": "Kopen",
"Subscribe": "Abonneren",
"Sample": "Voorbeeld",
"Download": "Downloaden",
"Open & Read": "Openen & Lezen",
"Tags": "Tags",
"Tag": "Tag",
"First": "Eerste",
"Previous": "Vorige",
"Next": "Volgende",
"Last": "Laatste",
"Cannot Load Page": "Pagina kan niet worden geladen",
"An error occurred": "Er is een fout opgetreden",
"Online Library": "Online Bibliotheek",
"URL must start with http:// or https://": "URL moet beginnen met http:// of https://",
"Title, Author, Tag, etc...": "Titel, Auteur, Tag, enzovoort...",
"Query": "Zoekopdracht",
"Subject": "Onderwerp",
"Enter {{terms}}": "Voer {{terms}} in",
"No search results found": "Geen zoekresultaten gevonden",
"Failed to load OPDS feed: {{status}} {{statusText}}": "Het laden van de OPDS-feed is mislukt: {{status}} {{statusText}}",
"Search in {{title}}": "Zoeken in {{title}}",
"Manage Storage": "Opslag beheren",
"Failed to load files": "Bestanden laden mislukt",
"Deleted {{count}} file(s)_one": "{{count}} bestand verwijderd",
"Deleted {{count}} file(s)_other": "{{count}} bestanden verwijderd",
"Failed to delete {{count}} file(s)_one": "Kon {{count}} bestand niet verwijderen",
"Failed to delete {{count}} file(s)_other": "Kon {{count}} bestanden niet verwijderen",
"Failed to delete files": "Bestanden verwijderen mislukt",
"Total Files": "Totaal aantal bestanden",
"Total Size": "Totale grootte",
"Quota": "Quota",
"Used": "Gebruikt",
"Files": "Bestanden",
"Search files...": "Bestanden zoeken...",
"Newest First": "Nieuwste eerst",
"Oldest First": "Oudste eerst",
"Largest First": "Grootste eerst",
"Smallest First": "Kleinste eerst",
"Name A-Z": "Naam A-Z",
"Name Z-A": "Naam Z-A",
"{{count}} selected_one": "{{count}} geselecteerd",
"{{count}} selected_other": "{{count}} geselecteerd",
"Delete Selected": "Verwijder geselecteerde",
"Created": "Gemaakt",
"No files found": "Geen bestanden gevonden",
"No files uploaded yet": "Nog geen bestanden geüpload",
"files": "bestanden",
"Page {{current}} of {{total}}": "Pagina {{current}} van {{total}}",
"Are you sure to delete {{count}} selected file(s)?_one": "Weet je zeker dat je {{count}} geselecteerd bestand wilt verwijderen?",
"Are you sure to delete {{count}} selected file(s)?_other": "Weet je zeker dat je {{count}} geselecteerde bestanden wilt verwijderen?",
"Cloud Storage Usage": "Cloudopslaggebruik",
"Rename Group": "Groep hernoemen",
"From Directory": "Vanuit map",
"Successfully imported {{count}} book(s)_one": "Succesvol 1 boek geïmporteerd",
"Successfully imported {{count}} book(s)_other": "Succesvol {{count}} boeken geïmporteerd",
"Count": "Aantal",
"Start Page": "Startpagina",
"Search in OPDS Catalog...": "Zoeken in OPDS-catalogus...",
"Please log in to use advanced TTS features": "Log in om geavanceerde TTS-functies te gebruiken",
"Word limit of 30 words exceeded.": "De limiet van 30 woorden is overschreden.",
"Proofread": "Correctie",
"Current selection": "Huidige selectie",
"All occurrences in this book": "Alle voorkomens in dit boek",
"All occurrences in your library": "Alle voorkomens in je bibliotheek",
"Selected text:": "Geselecteerde tekst:",
"Replace with:": "Vervangen door:",
"Enter text...": "Tekst invoeren…",
"Case sensitive:": "Hoofdlettergevoelig:",
"Scope:": "Bereik:",
"Selection": "Selectie",
"Library": "Bibliotheek",
"Yes": "Ja",
"No": "Nee",
"Proofread Replacement Rules": "Correctie-vervangingsregels",
"Selected Text Rules": "Regels voor geselecteerde tekst",
"No selected text replacement rules": "Geen vervangingsregels voor geselecteerde tekst",
"Book Specific Rules": "Boekspecifieke regels",
"No book-level replacement rules": "Geen vervangingsregels op boekniveau",
"Disable Quick Action": "Snelle actie uitschakelen",
"Enable Quick Action on Selection": "Snelle actie bij selectie inschakelen",
"None": "Geen",
"Annotation Tools": "Annotatiehulpmiddelen",
"Enable Quick Actions": "Snelle acties inschakelen",
"Quick Action": "Snelle actie",
"Copy to Notebook": "Kopiëren naar notitieboek",
"Copy text after selection": "Kopieer tekst na selectie",
"Highlight text after selection": "Markeer tekst na selectie",
"Annotate text after selection": "Annoteren tekst na selectie",
"Search text after selection": "Zoek tekst na selectie",
"Look up text in dictionary after selection": "Zoek tekst op in woordenboek na selectie",
"Look up text in Wikipedia after selection": "Zoek tekst op in Wikipedia na selectie",
"Translate text after selection": "Vertaal tekst na selectie",
"Read text aloud after selection": "Lees tekst hardop na selectie",
"Proofread text after selection": "Corrigeer tekst na selectie",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} actief, {{pendingCount}} wachtend",
"{{failedCount}} failed": "{{failedCount}} mislukt",
"Waiting...": "Wachten...",
"Failed": "Mislukt",
"Completed": "Voltooid",
"Cancelled": "Geannuleerd",
"Retry": "Opnieuw proberen",
"Active": "Actief",
"Transfer Queue": "Overdrachtwachtrij",
"Upload All": "Alles uploaden",
"Download All": "Alles downloaden",
"Resume Transfers": "Overdrachten hervatten",
"Pause Transfers": "Overdrachten pauzeren",
"Pending": "Wachtend",
"No transfers": "Geen overdrachten",
"Retry All": "Alles opnieuw proberen",
"Clear Completed": "Voltooide wissen",
"Clear Failed": "Mislukte wissen",
"Upload queued: {{title}}": "Upload in wachtrij: {{title}}",
"Download queued: {{title}}": "Download in wachtrij: {{title}}",
"Book not found in library": "Boek niet gevonden in bibliotheek",
"Unknown error": "Onbekende fout",
"Please log in to continue": "Log in om door te gaan",
"Cloud File Transfers": "Cloud Bestandoverdrachten",
"Show Search Results": "Zoekresultaten tonen",
"Search results for '{{term}}'": "Resultaten voor '{{term}}'",
"Close Search": "Zoekopdracht sluiten",
"Previous Result": "Vorig resultaat",
"Next Result": "Volgend resultaat",
"Bookmarks": "Bladwijzers",
"Annotations": "Aantekeningen",
"Show Results": "Resultaten tonen",
"Clear search": "Zoekopdracht wissen",
"Clear search history": "Zoekgeschiedenis wissen",
"Tap to Toggle Footer": "Tik om voettekst te wisselen",
"Show Current Time": "Huidige tijd weergeven",
"Use 24 Hour Clock": "24-uurs klok gebruike",
"Show Current Battery Status": "Toon huidige batterijstatus",
"Exported successfully": "Succesvol geëxporteerd",
"Book exported successfully.": "Boek succesvol geëxporteerd.",
"Failed to export the book.": "Exporteren van het boek mislukt.",
"Export Book": "Boek exporteren",
"Whole word:": "Heel woord:",
"Error": "Fout",
"Unable to load the article. Try searching directly on {{link}}.": "Kan het artikel niet laden. Probeer direct te zoeken op {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Kan het woord niet laden. Probeer direct te zoeken op {{link}}.",
"Date Published": "Publicatiedatum",
"Only for TTS:": "Alleen voor TTS:",
"Uploaded": "Geüpload",
"Downloaded": "Gedownload",
"Deleted": "Verwijderd",
"Note:": "Notitie:",
"Time:": "Tijd:",
"Format Options": "Formaatopties",
"Export Date": "Exportdatum",
"Chapter Titles": "Hoofdstuktitels",
"Chapter Separator": "Hoofdstukscheiding",
"Highlights": "Markeringen",
"Note Date": "Notitiedatum",
"Advanced": "Geavanceerd",
"Hide": "Verbergen",
"Show": "Tonen",
"Use Custom Template": "Aangepast sjabloon gebruiken",
"Export Template": "Exportsjabloon",
"Template Syntax:": "Sjabloonsyntaxis:",
"Insert value": "Waarde invoegen",
"Format date (locale)": "Datum opmaken (lokaal)",
"Format date (custom)": "Datum opmaken (aangepast)",
"Conditional": "Voorwaardelijk",
"Loop": "Lus",
"Available Variables:": "Beschikbare variabelen:",
"Book title": "Boektitel",
"Book author": "Boekauteur",
"Export date": "Exportdatum",
"Array of chapters": "Reeks hoofdstukken",
"Chapter title": "Hoofdstuktitel",
"Array of annotations": "Reeks annotaties",
"Highlighted text": "Gemarkeerde tekst",
"Annotation note": "Annotatienotitie",
"Date Format Tokens:": "Datumformaattokens:",
"Year (4 digits)": "Jaar (4 cijfers)",
"Month (01-12)": "Maand (01-12)",
"Day (01-31)": "Dag (01-31)",
"Hour (00-23)": "Uur (00-23)",
"Minute (00-59)": "Minuut (00-59)",
"Second (00-59)": "Seconde (00-59)",
"Show Source": "Bron tonen",
"No content to preview": "Geen inhoud om te bekijken",
"Export": "Exporteren",
"Set Timeout": "Time-out instellen",
"Select Voice": "Stem selecteren",
"Toggle Sticky Bottom TTS Bar": "Vaste TTS-balk schakelen",
"Display what I'm reading on Discord": "Toon wat ik lees op Discord",
"Show on Discord": "Toon op Discord",
"Instant {{action}}": "Directe {{action}}",
"Instant {{action}} Disabled": "Directe {{action}} uitgeschakeld",
"Annotation": "Annotatie",
"Reset Template": "Sjabloon resetten",
"Annotation style": "Annotatiestijl",
"Annotation color": "Annotatiekleur",
"Annotation time": "Annotatietijd",
"AI": "AI",
"Are you sure you want to re-index this book?": "Weet u zeker dat u dit boek opnieuw wilt indexeren?",
"Enable AI in Settings": "AI inschakelen in Instellingen",
"Index This Book": "Dit boek indexeren",
"Enable AI search and chat for this book": "AI-zoeken en chat voor dit boek inschakelen",
"Start Indexing": "Indexeren starten",
"Indexing book...": "Boek wordt geïndexeerd...",
"Preparing...": "Voorbereiden...",
"Delete this conversation?": "Dit gesprek verwijderen?",
"No conversations yet": "Nog geen gesprekken",
"Start a new chat to ask questions about this book": "Start een nieuwe chat om vragen te stellen over dit boek",
"Rename": "Hernoemen",
"New Chat": "Nieuwe chat",
"Chat": "Chat",
"Please enter a model ID": "Voer een model-ID in",
"Model not available or invalid": "Model niet beschikbaar of ongeldig",
"Failed to validate model": "Model valideren mislukt",
"Couldn't connect to Ollama. Is it running?": "Kon geen verbinding maken met Ollama. Is het actief?",
"Invalid API key or connection failed": "Ongeldige API-sleutel of verbinding mislukt",
"Connection failed": "Verbinding mislukt",
"AI Assistant": "AI-assistent",
"Enable AI Assistant": "AI-assistent inschakelen",
"Provider": "Provider",
"Ollama (Local)": "Ollama (Lokaal)",
"AI Gateway (Cloud)": "AI-gateway (Cloud)",
"Ollama Configuration": "Ollama-configuratie",
"Refresh Models": "Modellen vernieuwen",
"AI Model": "AI-model",
"No models detected": "Geen modellen gedetecteerd",
"AI Gateway Configuration": "AI-gateway configuratie",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Kies uit een selectie van hoogwaardige, voordelige AI-modellen. U kunt ook uw eigen model gebruiken door hieronder \"Aangepast model\" te selecteren.",
"API Key": "API-sleutel",
"Get Key": "Sleutel ophalen",
"Model": "Model",
"Custom Model...": "Aangepast model...",
"Custom Model ID": "Aangepast model-ID",
"Validate": "Valideren",
"Model available": "Model beschikbaar",
"Connection": "Verbinding",
"Test Connection": "Verbinding testen",
"Connected": "Verbonden",
"Custom Colors": "Aangepaste kleuren",
"Color E-Ink Mode": "Kleur E-Ink modus",
"Reading Ruler": "Leesliniaal",
"Enable Reading Ruler": "Leesliniaal inschakelen",
"Lines to Highlight": "Regels om te markeren",
"Ruler Color": "Kleur van liniaal",
"Command Palette": "Opdrachtenpalet",
"Search settings and actions...": "Zoek instellingen en acties...",
"No results found for": "Geen resultaten gevonden voor",
"Type to search settings and actions": "Typ om instellingen en acties te zoeken",
"Recent": "Recent",
"navigate": "navigeren",
"select": "selecteren",
"close": "sluiten",
"Search Settings": "Instellingen zoeken",
"Page Margins": "Paginamarges",
"AI Provider": "AI-provider",
"Ollama URL": "Ollama-URL",
"Ollama Model": "Ollama-model",
"AI Gateway Model": "AI Gateway-model",
"Actions": "Acties",
"Navigation": "Navigatie",
"Set status for {{count}} book(s)_one": "Stel status in voor {{count}} boek",
"Set status for {{count}} book(s)_other": "Stel status in voor {{count}} boeken",
"Mark as Unread": "Markeren als ongelezen",
"Mark as Finished": "Markeren als voltooid",
"Finished": "Voltooid",
"Unread": "Ongelezen",
"Clear Status": "Status wissen",
"Status": "Status",
"Loading": "Laden...",
"Exit Paragraph Mode": "Alineamodus verlaten",
"Paragraph Mode": "Alineamodus",
"Embedding Model": "Insluitmodel",
"{{count}} book(s) synced_one": "{{count}} boek gesynchroniseerd",
"{{count}} book(s) synced_other": "{{count}} boeken gesynchroniseerd",
"Unable to start RSVP": "Kan RSVP niet starten",
"RSVP not supported for PDF": "RSVP niet ondersteund voor PDF",
"Select Chapter": "Hoofdstuk selecteren",
"Context": "Context",
"Ready": "Klaar",
"Chapter Progress": "Hoofdstukvoortgang",
"words": "woorden",
"{{time}} left": "{{time}} over",
"Reading progress": "Leesvoortgang",
"Skip back 15 words": "15 woorden terug",
"Back 15 words (Shift+Left)": "15 woorden terug (Shift+Links)",
"Pause (Space)": "Pauze (Spatie)",
"Play (Space)": "Afspelen (Spatie)",
"Skip forward 15 words": "15 woorden vooruit",
"Forward 15 words (Shift+Right)": "15 woorden vooruit (Shift+Rechts)",
"Decrease speed": "Snelheid verlagen",
"Slower (Left/Down)": "Langzamer (Links/Omlaag)",
"Increase speed": "Snelheid verhogen",
"Faster (Right/Up)": "Sneller (Rechts/Omhoog)",
"Start RSVP Reading": "Start RSVP-lezen",
"Choose where to start reading": "Kies waar u wilt beginnen met lezen",
"From Chapter Start": "Vanaf begin hoofdstuk",
"Start reading from the beginning of the chapter": "Begin met lezen aan het begin van het hoofdstuk",
"Resume": "Hervatten",
"Continue from where you left off": "Ga verder waar u was gebleven",
"From Current Page": "Vanaf huidige pagina",
"Start from where you are currently reading": "Begin waar u momenteel leest",
"From Selection": "Vanaf selectie",
"Speed Reading Mode": "Snelle leesmodus",
"Scroll left": "Naar links scrollen",
"Scroll right": "Naar rechts scrollen",
"Library Sync Progress": "Voortgang bibliotheeksynchronisatie",
"Back to library": "Terug naar bibliotheek",
"Group by...": "Groeperen op...",
"Export as Plain Text": "Exporteren als platte tekst",
"Export as Markdown": "Exporteren als Markdown",
"Show Page Navigation Buttons": "Navigatieknoppen",
"Page {{number}}": "Pagina {{number}}",
"highlight": "markering",
"underline": "onderstreping",
"squiggly": "gegolfd",
"red": "rood",
"violet": "paars",
"blue": "blauw",
"green": "groen",
"yellow": "geel",
"Select {{style}} style": "Selecteer {{style}} stijl",
"Select {{color}} color": "Selecteer {{color}} kleur",
"Close Book": "Boek sluiten",
"Speed Reading": "Snel lezen",
"Close Speed Reading": "Snel lezen sluiten",
"Authors": "Auteurs",
"Books": "Boeken",
"Groups": "Groepen",
"Back to TTS Location": "Terug naar TTS-locatie",
"Metadata": "Metadata",
"Image viewer": "Afbeeldingenviewer",
"Previous Image": "Vorige afbeelding",
"Next Image": "Volgende afbeelding",
"Zoomed": "Gezoomd",
"Zoom level": "Zoomniveau",
"Table viewer": "Tabelviewer",
"Unable to connect to Readwise. Please check your network connection.": "Kan geen verbinding maken met Readwise. Controleer uw netwerkverbinding.",
"Invalid Readwise access token": "Ongeldige Readwise-toegangstoken",
"Disconnected from Readwise": "Verbinding met Readwise verbroken",
"Never": "Nooit",
"Readwise Settings": "Readwise-instellingen",
"Connected to Readwise": "Verbonden met Readwise",
"Last synced: {{time}}": "Laatst gesynchroniseerd: {{time}}",
"Sync Enabled": "Synchronisatie ingeschakeld",
"Disconnect": "Verbinding verbreken",
"Connect your Readwise account to sync highlights.": "Verbind uw Readwise-account om markeringen te synchroniseren.",
"Get your access token at": "Verkrijg uw toegangstoken op",
"Access Token": "Toegangstoken",
"Paste your Readwise access token": "Plak uw Readwise-toegangstoken",
"Config": "Configuratie",
"Readwise Sync": "Readwise-synchronisatie",
"Push Highlights": "Markeringen verzenden",
"Highlights synced to Readwise": "Markeringen gesynchroniseerd met Readwise",
"Readwise sync failed: no internet connection": "Readwise-synchronisatie mislukt: geen internetverbinding",
"Readwise sync failed: {{error}}": "Readwise-synchronisatie mislukt: {{error}}",
"System Screen Brightness": "Systeemhelderheid van het scherm",
"Page:": "Pagina:",
"Page: {{number}}": "Pagina: {{number}}",
"Annotation page number": "Annotatiepaginanummer",
"Translating...": "Vertalen...",
"Show Battery Percentage": "Batterijpercentage weergeven",
"Hide Scrollbar": "Schuifbalk verbergen",
"Skip to last reading position": "Ga naar laatste leespositie",
"Show context": "Context tonen",
"Hide context": "Context verbergen",
"Decrease font size": "Lettergrootte verkleinen",
"Increase font size": "Lettergrootte vergroten",
"Focus": "Focus",
"Theme color": "Themakleur",
"Import failed": "Import mislukt",
"Available Formatters:": "Beschikbare opmaak:",
"Format date": "Datum opmaken",
"Markdown block quote (> per line)": "Markdown-blokcitaat (> per regel)",
"Newlines to <br>": "Regeleinden naar <br>",
"Change case": "Hoofdlettergebruik wijzigen",
"Trim whitespace": "Witruimte verwijderen",
"Truncate to n characters": "Inkorten tot n tekens",
"Replace text": "Tekst vervangen",
"Fallback value": "Terugvalwaarde",
"Get length": "Lengte ophalen",
"First/last element": "Eerste/laatste element",
"Join array": "Array samenvoegen",
"Backup failed: {{error}}": "Back-up mislukt: {{error}}",
"Select Backup": "Selecteer back-up",
"Restore failed: {{error}}": "Herstel mislukt: {{error}}",
"Backup & Restore": "Back-up & Herstel",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "Maak een back-up van uw bibliotheek of herstel vanuit een eerdere back-up. Herstel wordt samengevoegd met uw huidige bibliotheek.",
"Backup Library": "Bibliotheek back-uppen",
"Restore Library": "Bibliotheek herstellen",
"Creating backup...": "Back-up maken...",
"Restoring library...": "Bibliotheek herstellen...",
"{{current}} of {{total}} items": "{{current}} van {{total}} items",
"Backup completed successfully!": "Back-up succesvol voltooid!",
"Restore completed successfully!": "Herstel succesvol voltooid!",
"Your library has been saved to the selected location.": "Uw bibliotheek is opgeslagen op de geselecteerde locatie.",
"{{added}} books added, {{updated}} books updated.": "{{added}} boeken toegevoegd, {{updated}} boeken bijgewerkt.",
"Operation failed": "Bewerking mislukt",
"Loading library...": "Bibliotheek laden...",
"{{count}} books refreshed_one": "{{count}} boek vernieuwd",
"{{count}} books refreshed_other": "{{count}} boeken vernieuwd",
"Failed to refresh metadata": "Metadata vernieuwen mislukt",
"Refresh Metadata": "Metadata vernieuwen",
"Keyboard Shortcuts": "Sneltoetsen",
"View all keyboard shortcuts": "Alle sneltoetsen bekijken",
"Switch Sidebar Tab": "Zijbalktabblad wisselen",
"Toggle Notebook": "Notitieboek tonen/verbergen",
"Search in Book": "Zoeken in boek",
"Toggle Scroll Mode": "Scrollmodus wisselen",
"Toggle Select Mode": "Selectiemodus wisselen",
"Toggle Bookmark": "Bladwijzer wisselen",
"Toggle Text to Speech": "Tekst-naar-spraak wisselen",
"Play / Pause TTS": "TTS afspelen / pauzeren",
"Toggle Paragraph Mode": "Alineamodus wisselen",
"Highlight Selection": "Selectie markeren",
"Underline Selection": "Selectie onderstrepen",
"Annotate Selection": "Selectie annoteren",
"Search Selection": "Selectie zoeken",
"Copy Selection": "Selectie kopiëren",
"Translate Selection": "Selectie vertalen",
"Dictionary Lookup": "Opzoeken in woordenboek",
"Wikipedia Lookup": "Opzoeken op Wikipedia",
"Read Aloud Selection": "Selectie voorlezen",
"Proofread Selection": "Selectie proeflezen",
"Open Settings": "Instellingen openen",
"Open Command Palette": "Opdrachtenpalet openen",
"Show Keyboard Shortcuts": "Sneltoetsen tonen",
"Open Books": "Boeken openen",
"Toggle Fullscreen": "Volledig scherm wisselen",
"Close Window": "Venster sluiten",
"Quit App": "App afsluiten",
"Go Left / Previous Page": "Naar links / Vorige pagina",
"Go Right / Next Page": "Naar rechts / Volgende pagina",
"Go Up": "Omhoog",
"Go Down": "Omlaag",
"Previous Chapter": "Vorig hoofdstuk",
"Next Chapter": "Volgend hoofdstuk",
"Scroll Half Page Down": "Halve pagina naar beneden scrollen",
"Scroll Half Page Up": "Halve pagina naar boven scrollen",
"Save Note": "Notitie opslaan",
"Single Section Scroll": "Scrollen per sectie",
"General": "Algemeen",
"Text to Speech": "Tekst naar spraak",
"Zoom": "Zoom",
"Window": "Venster",
"Your Bookshelf": "Jouw boekenkast",
"TTS": "Spraak",
"Media Info": "Media-info",
"Update Frequency": "Updatefrequentie",
"Every Sentence": "Elke zin",
"Every Paragraph": "Elke alinea",
"Every Chapter": "Elk hoofdstuk",
"TTS Media Info Update Frequency": "TTS media-info updatefrequentie",
"Select reading speed": "Leessnelheid selecteren",
"Drag to seek": "Sleep om te zoeken",
"Punctuation Delay": "Leesteken-vertraging",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "Bevestig dat deze OPDS-verbinding via Readest-servers in de webapp wordt doorgestuurd voordat u doorgaat.",
"Custom Headers": "Aangepaste headers",
"Custom Headers (optional)": "Aangepaste headers (optioneel)",
"Add one header per line using \"Header-Name: value\".": "Voeg één header per regel toe met \"Header-Name: value\".",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "Ik begrijp dat deze OPDS-verbinding via Readest-servers in de webapp wordt doorgestuurd. Als ik Readest niet vertrouw met deze inloggegevens of headers, moet ik de native app gebruiken.",
"Unable to connect to Hardcover. Please check your network connection.": "Kan geen verbinding maken met Hardcover. Controleer uw netwerkverbinding.",
"Invalid Hardcover API token": "Ongeldig Hardcover API-token",
"Disconnected from Hardcover": "Verbinding met Hardcover verbroken",
"Hardcover Settings": "Hardcover-instellingen",
"Connected to Hardcover": "Verbonden met Hardcover",
"Connect your Hardcover account to sync reading progress and notes.": "Verbind uw Hardcover-account om leesvoortgang en notities te synchroniseren.",
"Get your API token from hardcover.app → Settings → API.": "Haal uw API-token op via hardcover.app → Instellingen → API.",
"API Token": "API-token",
"Paste your Hardcover API token": "Plak uw Hardcover API-token",
"Hardcover sync enabled for this book": "Hardcover-synchronisatie ingeschakeld voor dit boek",
"Hardcover sync disabled for this book": "Hardcover-synchronisatie uitgeschakeld voor dit boek",
"Hardcover Sync": "Hardcover-synchronisatie",
"Enable for This Book": "Inschakelen voor dit boek",
"Push Notes": "Notities verzenden",
"Enable Hardcover sync for this book first.": "Schakel eerst Hardcover-synchronisatie in voor dit boek.",
"No annotations or excerpts to sync for this book.": "Geen annotaties of fragmenten om te synchroniseren voor dit boek.",
"Configure Hardcover in Settings first.": "Configureer eerst Hardcover in de instellingen.",
"No new Hardcover note changes to sync.": "Geen nieuwe Hardcover-notitiewijzigingen om te synchroniseren.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover gesynchroniseerd: {{inserted}} nieuw, {{updated}} bijgewerkt, {{skipped}} ongewijzigd",
"Hardcover notes sync failed: {{error}}": "Synchronisatie van Hardcover-notities mislukt: {{error}}",
"Reading progress synced to Hardcover": "Leesvoortgang gesynchroniseerd met Hardcover",
"Hardcover progress sync failed: {{error}}": "Synchronisatie van Hardcover-voortgang mislukt: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "Bestaande bronidentificatie behouden",
"Toggle Toolbar": "Werkbalk in-/uitschakelen"
}
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,6 @@
"Auto Mode": "Modo Automático",
"Behavior": "Comportamento",
"Book": "Livro",
"Book Cover": "Capa do Livro",
"Bookmark": "Marcador",
"Cancel": "Cancelar",
"Chapter": "Capítulo",
@@ -46,7 +45,6 @@
"Horizontal Direction": "Direção Horizontal",
"Hyphenation": "Hifenização",
"Import Books": "Importar Livros",
"Language:": "Idioma:",
"Layout": "Layout",
"Light Mode": "Modo Claro",
"Loading...": "Carregando...",
@@ -68,8 +66,8 @@
"Paging Animation": "Animação de Página",
"Paragraph": "Parágrafo",
"Parallel Read": "Leitura Paralela",
"Published:": "Publicado:",
"Publisher:": "Editora:",
"Published": "Publicado",
"Publisher": "Editora",
"Reading Progress Synced": "Progresso de leitura sincronizado",
"Reload Page": "Recarregar Página",
"Reveal in File Explorer": "Mostrar no Explorador de Arquivos",
@@ -83,7 +81,6 @@
"Search...": "Pesquisar...",
"Select Book": "Selecionar Livro",
"Select Books": "Selecionar livros",
"Select Multiple Books": "Selecionar múltiplos livros",
"Sepia": "Sépia",
"Serif Font": "Fonte Serif",
"Show Book Details": "Mostrar Detalhes do Livro",
@@ -94,23 +91,21 @@
"Slow": "Lento",
"Solarized": "Solarizado",
"Speak": "Falar",
"Subjects:": "Assuntos:",
"Subjects": "Assuntos",
"System Fonts": "Fontes do Sistema",
"TTS not supported in this device": "TTS não suportado neste dispositivo",
"Theme Color": "Cor do Tema",
"Theme Mode": "Modo do Tema",
"Translate": "Traduzir",
"Translated Text": "Texto Traduzido",
"Unknown": "Desconhecido",
"Untitled": "Sem Título",
"Updated:": "Atualizado:",
"Updated": "Atualizado",
"Version {{version}}": "Versão {{version}}",
"Vertical Direction": "Direção Vertical",
"Welcome to your library. You can import your books here and read them anytime.": "Bem-vindo à sua biblioteca. Você pode importar seus livros aqui e lê-los a qualquer momento.",
"Wikipedia": "Wikipédia",
"Writing Mode": "Modo de Escrita",
"Your Library": "Sua Biblioteca",
"TTS not supported for PDF": "TTS não suportado para PDF",
"Override Book Font": "Sobrescrever Fonte do Livro",
"Apply to All Books": "Aplicar a todos os livros",
"Apply to This Book": "Aplicar a este livro",
@@ -120,6 +115,7 @@
"Book Details": "Detalhes do Livro",
"From Local File": "Do arquivo local",
"TOC": "Índice",
"Table of Contents": "Índice",
"Book uploaded: {{title}}": "Livro enviado: {{title}}",
"Failed to upload book: {{title}}": "Falha ao enviar livro: {{title}}",
"Book downloaded: {{title}}": "Livro baixado: {{title}}",
@@ -176,9 +172,6 @@
"Token": "Token",
"Your OTP token": "Seu token OTP",
"Verify token": "Verificar token",
"Sign in with Google": "Entrar com o Google",
"Sign in with Apple": "Entrar com o Apple",
"Sign in with GitHub": "Entrar com o GitHub",
"Account": "Conta",
"Failed to delete user. Please try again later.": "Falha ao excluir usuário. Por favor, tente novamente mais tarde.",
"Community Support": "Suporte da comunidade",
@@ -191,12 +184,11 @@
"RTL Direction": "Direção RTL",
"Maximum Column Height": "Altura Máxima da Coluna",
"Maximum Column Width": "Largura Máxima da Coluna",
"Continuous Scroll": "Rolagem Contínua",
"Fullscreen": "Tela Cheia",
"No supported files found. Supported formats: {{formats}}": "Nenhum arquivo suportado encontrado. Formatos suportados: {{formats}}",
"Drop to Import Books": "Arraste para Importar Livros",
"Custom": "Personalizado",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Todo o mundo é um palco,\nE todos os homens e mulheres são meros atores;\nEles têm suas saídas e suas entradas,\nE um homem em seu tempo desempenha muitos papéis,\nSeus atos sendo sete idades.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Todo o mundo é um palco,\nE todos os homens e mulheres são meros atores;\nEles têm suas saídas e suas entradas,\nE um homem em seu tempo desempenha muitos papéis,\nSeus atos sendo sete idades.\n\n— William Shakespeare",
"Custom Theme": "Tema Personalizado",
"Theme Name": "Nome do Tema",
"Text Color": "Cor do Texto",
@@ -223,9 +215,9 @@
"Auto Import on File Open": "Importação Automática ao Abrir Arquivo",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected.": "Nenhum capítulo detectado.",
"Failed to parse the EPUB file.": "Falha ao analisar o arquivo EPUB.",
"This book format is not supported.": "Este formato de livro não é suportado.",
"No chapters detected": "Nenhum capítulo detectado",
"Failed to parse the EPUB file": "Falha ao analisar o arquivo EPUB",
"This book format is not supported": "Este formato de livro não é suportado",
"Unable to fetch the translation. Please log in first and try again.": "Não foi possível buscar a tradução. Faça login primeiro e tente novamente.",
"Group": "Grupo",
"Always on Top": "Sempre no Topo",
@@ -244,7 +236,7 @@
"Downloading {{downloaded}} of {{contentLength}}": "Baixando {{downloaded}} de {{contentLength}}",
"Download finished": "Download concluído",
"DOWNLOAD & INSTALL": "BAIXAR E INSTALAR",
"Changelog:": "Notas de versão:",
"Changelog": "Notas de versão",
"Software Update": "Atualização de Software",
"Title": "Título",
"Date Read": "Data de leitura",
@@ -253,18 +245,15 @@
"Ascending": "Crescente",
"Descending": "Decrescente",
"Sort by...": "Ordenar por...",
"Added:": "Adicionado:",
"Format:": "Formato:",
"Added": "Adicionado",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description:": "Descrição:",
"Description": "Descrição",
"No description available": "Nenhuma descrição disponível",
"List": "Lista",
"Grid": "Grade",
"(from 'As You Like It', Act II)": "(de 'Como Gostais', Ato II)",
"Link Color": "Cor do Link",
"Volume Keys for Page Flip": "Teclas de Volume para Virar Página",
"Clicks for Page Flip": "Cliques para Virar Página",
"Swap Clicks Area": "Trocar Área de Cliques",
"Screen": "Tela",
"Orientation": "Orientação",
"Portrait": "Retrato",
@@ -273,7 +262,7 @@
"Checking for updates...": "Verificando atualizações...",
"Error checking for updates": "Erro ao verificar atualizações",
"Details": "Detalhes",
"File Size:": "Tamanho do arquivo:",
"File Size": "Tamanho do arquivo",
"Auto Detect": "Detectar Automaticamente",
"Next Section": "Próxima seção",
"Previous Section": "Seção anterior",
@@ -301,7 +290,6 @@
"Disable Translation": "Desativar tradução",
"Scroll": "Rolar",
"Overlap Pixels": "Sobreposição de Pixels",
"Click": "Clique",
"System Language": "Idioma do Sistema",
"Security": "Segurança",
"Allow JavaScript": "Permitir JavaScript",
@@ -316,7 +304,6 @@
"Synced at {{time}}": "Sincronizado às {{time}}",
"Never synced": "Nunca sincronizado",
"Show Remaining Time": "Mostrar Tempo Restante",
"Show Page Number": "Mostrar Número da Página",
"{{time}} min left in chapter": "{{time}} min restantes no capítulo",
"Override Book Color": "Substituir Cor do Livro",
"Login Required": "Login necessário",
@@ -340,7 +327,6 @@
"Left Margin (px)": "Margem esquerda (px)",
"Column Gap (%)": "Espaço entre colunas (%)",
"Always Show Status Bar": "Exibir sempre a barra de status",
"Translation Not Available": "Tradução não disponível",
"Custom Content CSS": "CSS do conteúdo",
"Enter CSS for book content styling...": "Insira o CSS para o estilo do conteúdo do livro...",
"Custom Reader UI CSS": "CSS da interface",
@@ -350,12 +336,12 @@
"Fit": "Encaixar",
"Reset {{settings}}": "Redefinir {{settings}}",
"Reset Settings": "Redefinir Configurações",
"{{count}} pages left in chapter_one": "Falta {{count}} página neste capítulo",
"{{count}} pages left in chapter_many": "Faltam {{count}} páginas neste capítulo",
"{{count}} pages left in chapter_other": "Faltam {{count}} páginas neste capítulo",
"{{count}} pages left in chapter_one": "<1>Falta </1><0>{{count}}</0><1> página neste capítulo</1>",
"{{count}} pages left in chapter_many": "<1>Faltam </1><0>{{count}}</0><1> páginas neste capítulo</1>",
"{{count}} pages left in chapter_other": "<1>Faltam </1><0>{{count}}</0><1> páginas neste capítulo</1>",
"Show Remaining Pages": "Mostrar páginas restantes",
"Source Han Serif CN VF": "Source Han Serif",
"Huiwen-mincho": "Huiwen Mincho",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Gerenciar assinatura",
"Coming Soon": "Em breve",
@@ -363,7 +349,6 @@
"Upgrade to Plus or Pro": "Atualizar para Plus ou Pro",
"Current Plan": "Plano atual",
"Plan Limits": "Limites do plano",
"Failed to manage subscription. Please try again later.": "Não foi possível gerenciar a assinatura. Tente novamente mais tarde.",
"Processing your payment...": "Processando seu pagamento...",
"Please wait while we confirm your subscription.": "Por favor, aguarde enquanto confirmamos sua assinatura.",
"Payment Processing": "Processando pagamento",
@@ -376,7 +361,6 @@
"Email:": "E-mail:",
"Plan:": "Plano:",
"Amount:": "Valor:",
"Subscription ID:": "ID da assinatura:",
"Go to Library": "Ir para a biblioteca",
"Need help? Contact our support team at support@readest.com": "Precisa de ajuda? Entre em contato com nossa equipe de suporte: support@readest.com",
"Free Plan": "Plano gratuito",
@@ -406,7 +390,6 @@
"Listen without limits—convert as much text as you like into immersive audio.": "Ouça sem limites—converta tanto texto quanto quiser em áudio envolvente.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Desbloqueie recursos aprimorados de tradução com mais uso diário e opções avançadas.",
"DeepL Pro Access": "Acesso ao DeepL Pro",
"2 GB Cloud Sync Storage": "2 GB de Armazenamento na Nuvem",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Desfrute de respostas mais rápidas e assistência dedicada sempre que precisar de ajuda.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Cota diária de tradução atingida. Atualize seu plano para continuar usando traduções por IA.",
"Includes All Plus Plan Benefits": "Inclui Todos os Benefícios do Plano Plus",
@@ -416,10 +399,802 @@
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Aproveite ferramentas de IA poderosas para leitura inteligente, tradução e descoberta de conteúdo.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Traduza até 100.000 caracteres diariamente com o motor de tradução mais preciso disponível.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Traduza até 500.000 caracteres diariamente com o motor de tradução mais preciso disponível.",
"10 GB Cloud Sync Storage": "10 GB de Armazenamento na Nuvem",
"Securely store and access your entire reading collection with up to 2 GB of cloud storage.": "Armazene e acesse com segurança sua coleção completa de leitura com até 2 GB de armazenamento na nuvem.",
"Securely store and access your entire reading collection with up to 10 GB of cloud storage.": "Armazene e acesse com segurança sua coleção completa de leitura com até 10 GB de armazenamento na nuvem.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Armazene e acesse com segurança sua coleção completa de leitura com até 5 GB de armazenamento na nuvem.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Armazene e acesse com segurança sua coleção completa de leitura com até 20 GB de armazenamento na nuvem.",
"Deleted cloud backup of the book: {{title}}": "Backup na nuvem do livro excluído: {{title}}",
"Failed to delete cloud backup of the book": "Falha ao excluir o backup na nuvem do livro.",
"Are you sure to delete the cloud backup of the selected book?": "Tem certeza de que deseja excluir o backup na nuvem do livro selecionado?"
"Are you sure to delete the cloud backup of the selected book?": "Tem certeza de que deseja excluir o backup na nuvem do livro selecionado?",
"What's New in Readest": "Novidades no Readest",
"Enter book title": "Digite o título do livro",
"Subtitle": "Subtítulo",
"Enter book subtitle": "Digite o subtítulo do livro",
"Enter author name": "Digite o nome do autor",
"Series": "Série",
"Enter series name": "Digite o nome da série",
"Series Index": "Número da série",
"Enter series index": "Digite o número da série",
"Total in Series": "Total na série",
"Enter total books in series": "Digite o total de livros na série",
"Enter publisher": "Digite a editora",
"Publication Date": "Data de publicação",
"Identifier": "Identificador",
"Enter book description": "Digite a descrição do livro",
"Change cover image": "Alterar imagem da capa",
"Replace": "Substituir",
"Unlock cover": "Desbloquear capa",
"Lock cover": "Bloquear capa",
"Auto-Retrieve Metadata": "Recuperar metadados automaticamente",
"Auto-Retrieve": "Recuperação automática",
"Unlock all fields": "Desbloquear todos os campos",
"Unlock All": "Desbloquear tudo",
"Lock all fields": "Bloquear todos os campos",
"Lock All": "Bloquear tudo",
"Reset": "Redefinir",
"Edit Metadata": "Editar metadados",
"Locked": "Bloqueado",
"Select Metadata Source": "Selecionar fonte de metadados",
"Keep manual input": "Manter entrada manual",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Ficção, Ciência, História",
"Open Book in New Window": "Abrir livro em nova janela",
"Voices for {{lang}}": "Vozes para {{lang}}",
"Yandex Translate": "Yandex Translate",
"YYYY or YYYY-MM-DD": "YYYY ou YYYY-MM-DD",
"Restore Purchase": "Restaurar Compra",
"No purchases found to restore.": "Nenhuma compra encontrada para restaurar.",
"Failed to restore purchases.": "Falha ao restaurar compras.",
"Failed to manage subscription.": "Falha ao gerenciar assinatura.",
"Failed to load subscription plans.": "Falha ao carregar planos de assinatura.",
"year": "ano",
"Failed to create checkout session": "Falha ao criar sessão de checkout",
"Storage": "Armazenamento",
"Terms of Service": "Termos de Serviço",
"Privacy Policy": "Política de Privacidade",
"Disable Double Click": "Desativar Clique Duplo",
"TTS not supported for this document": "TTS não suportado para este documento",
"Reset Password": "Redefinir Senha",
"Show Reading Progress": "Mostrar Progresso de Leitura",
"Reading Progress Style": "Estilo de Progresso de Leitura",
"Page Number": "Número da Página",
"Percentage": "Porcentagem",
"Deleted local copy of the book: {{title}}": " cópia local do livro excluída: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Falha ao excluir backup na nuvem do livro: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Falha ao excluir cópia local do livro: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Tem certeza de que deseja excluir a cópia local do livro selecionado?",
"Remove from Cloud & Device": "Remover da Nuvem & Dispositivo",
"Remove from Cloud Only": "Remover apenas da Nuvem",
"Remove from Device Only": "Remover apenas do Dispositivo",
"Disconnected": "Desconectado",
"KOReader Sync Settings": "Configurações de Sincronização KOReader",
"Sync Strategy": "Estratégia de Sincronização",
"Ask on conflict": "Perguntar em caso de conflito",
"Always use latest": "Sempre usar o mais recente",
"Send changes only": "Enviar apenas alterações",
"Receive changes only": "Receber apenas alterações",
"Checksum Method": "Método de Verificação",
"File Content (recommended)": "Conteúdo do Arquivo (recomendado)",
"File Name": "Nome do Arquivo",
"Device Name": "Nome do Dispositivo",
"Connect to your KOReader Sync server.": "Conectar ao seu servidor KOReader Sync.",
"Server URL": "URL do Servidor",
"Username": "Nome de Usuário",
"Your Username": "Seu Nome de Usuário",
"Password": "Senha",
"Connect": "Conectar",
"KOReader Sync": "KOReader Sync",
"Sync Conflict": "Conflito de Sincronização",
"Sync reading progress from \"{{deviceName}}\"?": "Sincronizar progresso de leitura de \"{{deviceName}}\"?",
"another device": "outro dispositivo",
"Local Progress": "Progresso Local",
"Remote Progress": "Progresso Remoto",
"Page {{page}} of {{total}} ({{percentage}}%)": "Página {{page}} de {{total}} ({{percentage}}%)",
"Current position": "Posição Atual",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Aproximadamente página {{page}} de {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Aproximadamente {{percentage}}%",
"Failed to connect": "Falha ao conectar",
"Sync Server Connected": "Servidor de Sincronização Conectado",
"Sync as {{userDisplayName}}": "Sincronizar como {{userDisplayName}}",
"Custom Fonts": "Fontes Personalizadas",
"Cancel Delete": "Cancelar Exclusão",
"Import Font": "Importar Fonte",
"Delete Font": "Excluir Fonte",
"Tips": "Dicas",
"Custom fonts can be selected from the Font Face menu": "Fontes personalizadas podem ser selecionadas no menu Fonte",
"Manage Custom Fonts": "Gerenciar Fontes Personalizadas",
"Select Files": "Selecionar Arquivos",
"Select Image": "Selecionar Imagem",
"Select Video": "Selecionar Vídeo",
"Select Audio": "Selecionar Áudio",
"Select Fonts": "Selecionar Fontes",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Formatos de fonte suportados: .ttf, .otf, .woff, .woff2",
"Push Progress": "Enviar Progresso",
"Pull Progress": "Obter Progresso",
"Previous Paragraph": "Parágrafo anterior",
"Previous Sentence": "Frase anterior",
"Pause": "Pausar",
"Play": "Reproduzir",
"Next Sentence": "Próxima frase",
"Next Paragraph": "Próximo parágrafo",
"Separate Cover Page": "Páginas de Capa Separadas",
"Resize Notebook": "Redimensionar Caderno",
"Resize Sidebar": "Redimensionar Barra Lateral",
"Get Help from the Readest Community": "Obter ajuda da comunidade Readest",
"Remove cover image": "Remover imagem da capa",
"Bookshelf": "Estante de Livros",
"View Menu": "Ver Menu",
"Settings Menu": "Menu de Configurações",
"View account details and quota": "Ver detalhes da conta e cota",
"Library Header": "Cabeçalho da Biblioteca",
"Book Content": "Conteúdo do Livro",
"Footer Bar": "Barra de Rodapé",
"Header Bar": "Barra de Cabeçalho",
"View Options": "Opções de Visualização",
"Book Menu": "Menu do Livro",
"Search Options": "Opções de Pesquisa",
"Close": "Fechar",
"Delete Book Options": "Opções de Exclusão de Livro",
"ON": "LIGADO",
"OFF": "DESLIGADO",
"Reading Progress": "Progresso de Leitura",
"Page Margin": "Margem da Página",
"Remove Bookmark": "Remover Marcador",
"Add Bookmark": "Adicionar Marcador",
"Books Content": "Conteúdo dos Livros",
"Jump to Location": "Ir para Localização",
"Unpin Notebook": "Desafixar Caderno",
"Pin Notebook": "Fixar Caderno",
"Hide Search Bar": "Ocultar Barra de Pesquisa",
"Show Search Bar": "Mostrar Barra de Pesquisa",
"On {{current}} of {{total}} page": "Na {{current}} de {{total}} página",
"Section Title": "Título da Seção",
"Decrease": "Diminuir",
"Increase": "Aumentar",
"Settings Panels": "Painéis de Configurações",
"Settings": "Configurações",
"Unpin Sidebar": "Desafixar Barra Lateral",
"Pin Sidebar": "Fixar Barra Lateral",
"Toggle Sidebar": "Alternar Barra Lateral",
"Toggle Translation": "Alternar Tradução",
"Translation Disabled": "Tradução Desativada",
"Minimize": "Minimizar",
"Maximize or Restore": "Maximizar ou Restaurar",
"Exit Parallel Read": "Sair da Leitura Paralela",
"Enter Parallel Read": "Entrar na Leitura Paralela",
"Zoom Level": "Nivel de Zoom",
"Zoom Out": "Reduzir Zoom",
"Reset Zoom": "Redefinir Zoom",
"Zoom In": "Aumentar Zoom",
"Zoom Mode": "Modo de Zoom",
"Single Page": "Página Única",
"Auto Spread": "Espalhamento Automático",
"Fit Page": "Ajustar Página",
"Fit Width": "Ajustar Largura",
"Failed to select directory": "Falha ao selecionar diretório",
"The new data directory must be different from the current one.": "O novo diretório de dados deve ser diferente do atual.",
"Migration failed: {{error}}": "A migração falhou: {{error}}",
"Change Data Location": "Alterar Localização dos Dados",
"Current Data Location": "Localização Atual dos Dados",
"Total size: {{size}}": "Tamanho total: {{size}}",
"Calculating file info...": "Calculando informações do arquivo...",
"New Data Location": "Nova Localização dos Dados",
"Choose Different Folder": "Escolher Pasta Diferente",
"Choose New Folder": "Escolher Nova Pasta",
"Migrating data...": "Migrando dados...",
"Copying: {{file}}": "Copiando: {{file}}",
"{{current}} of {{total}} files": "{{current}} de {{total}} arquivos",
"Migration completed successfully!": "Migração concluída com sucesso!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Seus dados foram movidos para a nova localização. Reinicie o aplicativo para concluir o processo.",
"Migration failed": "Migração falhou",
"Important Notice": "Aviso Importante",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Isso moverá todos os dados do seu aplicativo para a nova localização. Certifique-se de que o destino tenha espaço livre suficiente.",
"Restart App": "Reiniciar Aplicativo",
"Start Migration": "Iniciar Migração",
"Advanced Settings": "Configurações Avançadas",
"File count: {{size}}": "Contagem de arquivos: {{size}}",
"Background Read Aloud": "Leitura em Segundo Plano",
"Ready to read aloud": "Pronto para leitura em voz alta",
"Read Aloud": "Ler em Voz Alta",
"Screen Brightness": "Brilho da Tela",
"Background Image": "Imagem de Fundo",
"Import Image": "Importar Imagem",
"Opacity": "Opacidade",
"Size": "Tamanho",
"Cover": "Capa",
"Contain": "Contém",
"{{number}} pages left in chapter": "<1>Faltam </1><0>{{number}}</0><1> páginas neste capítulo</1>",
"Device": "Dispositivo",
"E-Ink Mode": "Modo E-Ink",
"Highlight Colors": "Cores de Destaque",
"Pagination": "Paginação",
"Disable Double Tap": "Desativar Toque Duplo",
"Tap to Paginate": "Toque para Paginar",
"Click to Paginate": "Clique para Paginar",
"Tap Both Sides": "Toque em Ambos os Lados",
"Click Both Sides": "Clique em Ambos os Lados",
"Swap Tap Sides": "Trocar Lados do Toque",
"Swap Click Sides": "Trocar Lados do Clique",
"Source and Translated": "Fonte e Traduzido",
"Translated Only": "Apenas Traduzido",
"Source Only": "Apenas Fonte",
"TTS Text": "TTS Texto",
"The book file is corrupted": "O arquivo do livro está corrompido",
"The book file is empty": "O arquivo do livro está vazio",
"Failed to open the book file": "Falha ao abrir o arquivo do livro",
"On-Demand Purchase": "Compra sob demanda",
"Full Customization": "Personalização Completa",
"Lifetime Plan": "Plano Vitalício",
"One-Time Payment": "Pagamento Único",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Faça um único pagamento para desfrutar de acesso vitalício a recursos específicos em todos os dispositivos. Compre recursos ou serviços específicos apenas quando precisar deles.",
"Expand Cloud Sync Storage": "Expandir Armazenamento de Sincronização em Nuvem",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Expanda seu armazenamento em nuvem para sempre com uma compra única. Cada compra adicional adiciona mais espaço.",
"Unlock All Customization Options": "Desbloquear Todas as Opções de Personalização",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Desbloquear temas adicionais, fontes, opções de layout e leitura em voz alta, tradutores, serviços de armazenamento em nuvem.",
"Purchase Successful!": "Compra Bem-Sucedida!",
"lifetime": "vitalício",
"Thank you for your purchase! Your payment has been processed successfully.": "Obrigado pela sua compra! Seu pagamento foi processado com sucesso.",
"Order ID:": "ID do Pedido:",
"TTS Highlighting": "Destaque TTS",
"Style": "Estilo",
"Underline": "Sublinhado",
"Strikethrough": "Tachado",
"Squiggly": "Ondulado",
"Outline": "Contorno",
"Save Current Color": "Salvar cor atual",
"Quick Colors": "Cores rápidas",
"Highlighter": "Marcador",
"Save Book Cover": "Salvar Capa do Livro",
"Auto-save last book cover": "Salvar automaticamente a última capa do livro",
"Back": "Voltar",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "E-mail de confirmação enviado! Verifique os seus endereços de e-mail antigo e novo para confirmar a alteração.",
"Failed to update email": "Falha ao atualizar o e-mail",
"New Email": "Novo e-mail",
"Your new email": "O seu novo e-mail",
"Updating email ...": "A atualizar o e-mail...",
"Update email": "Atualizar e-mail",
"Current email": "E-mail atual",
"Update Email": "Atualizar e-mail",
"All": "Todos",
"Unable to open book": "Não foi possível abrir o livro",
"Punctuation": "Pontuação",
"Replace Quotation Marks": "Substituir Aspas",
"Enabled only in vertical layout.": "Habilitado apenas no layout vertical.",
"No Conversion": "Sem conversão",
"Simplified to Traditional": "Simplificado → Tradicional",
"Traditional to Simplified": "Tradicional → Simplificado",
"Simplified to Traditional (Taiwan)": "Simplificado → Tradicional (Taiwan)",
"Simplified to Traditional (Hong Kong)": "Simplificado → Tradicional (Hong Kong)",
"Simplified to Traditional (Taiwan), with phrases": "Simplificado → Tradicional (Taiwan • frases)",
"Traditional (Taiwan) to Simplified": "Tradicional (Taiwan) → Simplificado",
"Traditional (Hong Kong) to Simplified": "Tradicional (Hong Kong) → Simplificado",
"Traditional (Taiwan) to Simplified, with phrases": "Tradicional (Taiwan • frases) → Simplificado",
"Convert Simplified and Traditional Chinese": "Converter Chinês Simpl./Trad.",
"Convert Mode": "Modo de conversão",
"Failed to auto-save book cover for lock screen: {{error}}": "Falha ao salvar automaticamente a capa do livro para a tela de bloqueio: {{error}}",
"Download from Cloud": "Baixar da Nuvem",
"Upload to Cloud": "Enviar para a Nuvem",
"Clear Custom Fonts": "Limpar Fontes Personalizadas",
"Columns": "Colunas",
"OPDS Catalogs": "Catálogos OPDS",
"Adding LAN addresses is not supported in the web app version.": "Adicionar endereços LAN não é suportado na versão web.",
"Invalid OPDS catalog. Please check the URL.": "Catálogo OPDS inválido. Verifique o URL.",
"Browse and download books from online catalogs": "Navegar e baixar livros de catálogos online",
"My Catalogs": "Meus catálogos",
"Add Catalog": "Adicionar catálogo",
"No catalogs yet": "Nenhum catálogo ainda",
"Add your first OPDS catalog to start browsing books": "Adicione seu primeiro catálogo OPDS para começar a navegar pelos livros",
"Add Your First Catalog": "Adicione seu primeiro catálogo",
"Browse": "Navegar",
"Popular Catalogs": "Catálogos populares",
"Add": "Adicionar",
"Add OPDS Catalog": "Adicionar catálogo OPDS",
"Catalog Name": "Nome do catálogo",
"My Calibre Library": "Minha biblioteca Calibre",
"OPDS URL": "URL do OPDS",
"Username (optional)": "Nome de usuário (opcional)",
"Password (optional)": "Senha (opcional)",
"Description (optional)": "Descrição (opcional)",
"A brief description of this catalog": "Uma breve descrição deste catálogo",
"Validating...": "Validando...",
"View All": "Ver todos",
"Forward": "Avançar",
"Home": "Início",
"{{count}} items_one": "{{count}} item",
"{{count}} items_many": "{{count}} itens",
"{{count}} items_other": "{{count}} item",
"Download completed": "Download concluído",
"Download failed": "Falha no download",
"Open Access": "Acesso aberto",
"Borrow": "Emprestar",
"Buy": "Comprar",
"Subscribe": "Assinar",
"Sample": "Amostra",
"Download": "Baixar",
"Open & Read": "Abrir e ler",
"Tags": "Etiquetas",
"Tag": "Etiqueta",
"First": "Pierwsza",
"Previous": "Poprzednia",
"Next": "Następna",
"Last": "Ostatnia",
"Cannot Load Page": "Nie można załadować strony",
"An error occurred": "Wystąpił błąd",
"Online Library": "Biblioteca online",
"URL must start with http:// or https://": "URL deve começar com http:// ou https://",
"Title, Author, Tag, etc...": "Título, Autor, Etiqueta, etc...",
"Query": "Consulta",
"Subject": "Assunto",
"Enter {{terms}}": "Insira {{terms}}",
"No search results found": "Nenhum resultado encontrado",
"Failed to load OPDS feed: {{status}} {{statusText}}": "Falha ao carregar o feed OPDS: {{status}} {{statusText}}",
"Search in {{title}}": "Pesquisar em {{title}}",
"Manage Storage": "Gerir Armazenamento",
"Failed to load files": "Falha ao carregar arquivos",
"Deleted {{count}} file(s)_one": "Apagado {{count}} ficheiro",
"Deleted {{count}} file(s)_many": "Apagados {{count}} ficheiros",
"Deleted {{count}} file(s)_other": "Apagado {{count}} ficheiro",
"Failed to delete {{count}} file(s)_one": "Falha ao apagar {{count}} ficheiro",
"Failed to delete {{count}} file(s)_many": "Falha ao apagar {{count}} ficheiros",
"Failed to delete {{count}} file(s)_other": "Falha ao apagar {{count}} ficheiro",
"Failed to delete files": "Falha ao apagar arquivos",
"Total Files": "Total de Arquivos",
"Total Size": "Tamanho Total",
"Quota": "Quota",
"Used": "Usado",
"Files": "Arquivos",
"Search files...": "Procurar arquivos...",
"Newest First": "Mais Recentes Primeiro",
"Oldest First": "Mais Antigos Primeiro",
"Largest First": "Maiores Primeiro",
"Smallest First": "Menores Primeiro",
"Name A-Z": "Nome A-Z",
"Name Z-A": "Nome Z-A",
"{{count}} selected_one": "{{count}} selecionado",
"{{count}} selected_many": "{{count}} selecionados",
"{{count}} selected_other": "{{count}} selecionado",
"Delete Selected": "Apagar Selecionados",
"Created": "Criado",
"No files found": "Nenhum arquivo encontrado",
"No files uploaded yet": "Nenhum arquivo enviado ainda",
"files": "arquivos",
"Page {{current}} of {{total}}": "Página {{current}} de {{total}}",
"Are you sure to delete {{count}} selected file(s)?_one": "Tem certeza de que deseja apagar {{count}} ficheiro selecionado?",
"Are you sure to delete {{count}} selected file(s)?_many": "Tem certeza de que deseja apagar {{count}} ficheiros selecionados?",
"Are you sure to delete {{count}} selected file(s)?_other": "Tem certeza de que deseja apagar {{count}} ficheiro selecionado?",
"Cloud Storage Usage": "Uso de Armazenamento na Nuvem",
"Rename Group": "Renomear Grupo",
"From Directory": "Do Diretório",
"Successfully imported {{count}} book(s)_one": "Importado com sucesso 1 livro",
"Successfully imported {{count}} book(s)_many": "Importados com sucesso {{count}} livros",
"Successfully imported {{count}} book(s)_other": "Importados com sucesso {{count}} livros",
"Count": "Contagem",
"Start Page": "Página Inicial",
"Search in OPDS Catalog...": "Pesquisar no Catálogo OPDS...",
"Please log in to use advanced TTS features": "Por favor, faça login para usar recursos avançados de TTS",
"Word limit of 30 words exceeded.": "O limite de 30 palavras foi excedido.",
"Proofread": "Revisão",
"Current selection": "Seleção atual",
"All occurrences in this book": "Todas as ocorrências neste livro",
"All occurrences in your library": "Todas as ocorrências na sua biblioteca",
"Selected text:": "Texto selecionado:",
"Replace with:": "Substituir por:",
"Enter text...": "Introduzir texto…",
"Case sensitive:": "Diferenciar maiúsculas e minúsculas:",
"Scope:": "Âmbito:",
"Selection": "Seleção",
"Library": "Biblioteca",
"Yes": "Sim",
"No": "Não",
"Proofread Replacement Rules": "Regras de substituição da revisão",
"Selected Text Rules": "Regras do texto selecionado",
"No selected text replacement rules": "Não existem regras de substituição para o texto selecionado",
"Book Specific Rules": "Regras específicas do livro",
"No book-level replacement rules": "Não existem regras de substituição ao nível do livro",
"Disable Quick Action": "Desativar Ação Rápida",
"Enable Quick Action on Selection": "Ativar Ação Rápida na Seleção",
"None": "Nenhum",
"Annotation Tools": "Ferramentas de Anotação",
"Enable Quick Actions": "Ativar Ações Rápidas",
"Quick Action": "Ação Rápida",
"Copy to Notebook": "Copiar para o Caderno",
"Copy text after selection": "Copiar texto após a seleção",
"Highlight text after selection": "Destacar texto após a seleção",
"Annotate text after selection": "Anotar texto após a seleção",
"Search text after selection": "Pesquisar texto após a seleção",
"Look up text in dictionary after selection": "Procurar texto no dicionário após a seleção",
"Look up text in Wikipedia after selection": "Procurar texto na Wikipedia após a seleção",
"Translate text after selection": "Traduzir texto após a seleção",
"Read text aloud after selection": "Ler texto em voz alta após a seleção",
"Proofread text after selection": "Revisar texto após a seleção",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} ativos, {{pendingCount}} pendentes",
"{{failedCount}} failed": "{{failedCount}} falharam",
"Waiting...": "Aguardando...",
"Failed": "Falhou",
"Completed": "Concluído",
"Cancelled": "Cancelado",
"Retry": "Tentar novamente",
"Active": "Ativos",
"Transfer Queue": "Fila de Transferências",
"Upload All": "Enviar Todos",
"Download All": "Baixar Todos",
"Resume Transfers": "Retomar Transferências",
"Pause Transfers": "Pausar Transferências",
"Pending": "Pendentes",
"No transfers": "Sem transferências",
"Retry All": "Tentar Todos Novamente",
"Clear Completed": "Limpar Concluídos",
"Clear Failed": "Limpar Falhos",
"Upload queued: {{title}}": "Upload na fila: {{title}}",
"Download queued: {{title}}": "Download na fila: {{title}}",
"Book not found in library": "Livro não encontrado na biblioteca",
"Unknown error": "Erro desconhecido",
"Please log in to continue": "Faça login para continuar",
"Cloud File Transfers": "Transferências de Arquivos",
"Show Search Results": "Mostrar resultados",
"Search results for '{{term}}'": "Resultados para '{{term}}'",
"Close Search": "Fechar pesquisa",
"Previous Result": "Resultado anterior",
"Next Result": "Próximo resultado",
"Bookmarks": "Marcadores",
"Annotations": "Anotações",
"Show Results": "Mostrar resultados",
"Clear search": "Limpar pesquisa",
"Clear search history": "Limpar histórico de pesquisa",
"Tap to Toggle Footer": "Toque para alternar rodapé",
"Show Current Time": "Mostrar hora atual",
"Use 24 Hour Clock": "Usar formato de 24 horas",
"Show Current Battery Status": "Mostrar o estado atual da bateria",
"Exported successfully": "Exportado com sucesso",
"Book exported successfully.": "Livro exportado com sucesso.",
"Failed to export the book.": "Falha ao exportar o livro.",
"Export Book": "Exportar livro",
"Whole word:": "Palavra inteira:",
"Error": "Erro",
"Unable to load the article. Try searching directly on {{link}}.": "Não foi possível carregar o artigo. Tente pesquisar diretamente em {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Não foi possível carregar a palavra. Tente pesquisar diretamente em {{link}}.",
"Date Published": "Data de publicação",
"Only for TTS:": "Apenas para TTS:",
"Uploaded": "Enviado",
"Downloaded": "Baixado",
"Deleted": "Excluído",
"Note:": "Nota:",
"Time:": "Hora:",
"Format Options": "Opções de formato",
"Export Date": "Data de exportação",
"Chapter Titles": "Títulos dos capítulos",
"Chapter Separator": "Separador de capítulos",
"Highlights": "Destaques",
"Note Date": "Data da nota",
"Advanced": "Avançado",
"Hide": "Ocultar",
"Show": "Mostrar",
"Use Custom Template": "Usar modelo personalizado",
"Export Template": "Modelo de exportação",
"Template Syntax:": "Sintaxe do modelo:",
"Insert value": "Inserir valor",
"Format date (locale)": "Formatar data (local)",
"Format date (custom)": "Formatar data (personalizado)",
"Conditional": "Condicional",
"Loop": "Loop",
"Available Variables:": "Variáveis disponíveis:",
"Book title": "Título do livro",
"Book author": "Autor do livro",
"Export date": "Data de exportação",
"Array of chapters": "Lista de capítulos",
"Chapter title": "Título do capítulo",
"Array of annotations": "Lista de anotações",
"Highlighted text": "Texto destacado",
"Annotation note": "Nota de anotação",
"Date Format Tokens:": "Tokens de formato de data:",
"Year (4 digits)": "Ano (4 dígitos)",
"Month (01-12)": "Mês (01-12)",
"Day (01-31)": "Dia (01-31)",
"Hour (00-23)": "Hora (00-23)",
"Minute (00-59)": "Minuto (00-59)",
"Second (00-59)": "Segundo (00-59)",
"Show Source": "Mostrar fonte",
"No content to preview": "Sem conteúdo para visualizar",
"Export": "Exportar",
"Set Timeout": "Definir tempo limite",
"Select Voice": "Selecionar voz",
"Toggle Sticky Bottom TTS Bar": "Alternar barra TTS fixada",
"Display what I'm reading on Discord": "Mostrar o que estou lendo no Discord",
"Show on Discord": "Mostrar no Discord",
"Instant {{action}}": "{{action}} instantâneo",
"Instant {{action}} Disabled": "{{action}} instantâneo desativado",
"Annotation": "Anotação",
"Reset Template": "Redefinir modelo",
"Annotation style": "Estilo de anotação",
"Annotation color": "Cor da anotação",
"Annotation time": "Hora da anotação",
"AI": "IA",
"Are you sure you want to re-index this book?": "Tem certeza de que deseja reindexar este livro?",
"Enable AI in Settings": "Ativar IA nas configurações",
"Index This Book": "Indexar este livro",
"Enable AI search and chat for this book": "Ativar pesquisa e chat com IA para este livro",
"Start Indexing": "Iniciar indexação",
"Indexing book...": "Indexando livro...",
"Preparing...": "Preparando...",
"Delete this conversation?": "Excluir esta conversa?",
"No conversations yet": "Ainda não há conversas",
"Start a new chat to ask questions about this book": "Inicie um novo chat para fazer perguntas sobre este livro",
"Rename": "Renomear",
"New Chat": "Novo chat",
"Chat": "Chat",
"Please enter a model ID": "Por favor, insira um ID de modelo",
"Model not available or invalid": "Modelo não disponível ou inválido",
"Failed to validate model": "Falha ao validar modelo",
"Couldn't connect to Ollama. Is it running?": "Não foi possível conectar ao Ollama. Está em execução?",
"Invalid API key or connection failed": "Chave API inválida ou falha na conexão",
"Connection failed": "Falha na conexão",
"AI Assistant": "Assistente de IA",
"Enable AI Assistant": "Ativar assistente de IA",
"Provider": "Provedor",
"Ollama (Local)": "Ollama (Local)",
"AI Gateway (Cloud)": "Gateway de IA (Nuvem)",
"Ollama Configuration": "Configuração do Ollama",
"Refresh Models": "Atualizar modelos",
"AI Model": "Modelo de IA",
"No models detected": "Nenhum modelo detectado",
"AI Gateway Configuration": "Configuração do gateway de IA",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Escolha entre uma seleção de modelos de IA de alta qualidade e econômicos. Você também pode usar seu próprio modelo selecionando \"Modelo personalizado\" abaixo.",
"API Key": "Chave API",
"Get Key": "Obter chave",
"Model": "Modelo",
"Custom Model...": "Modelo personalizado...",
"Custom Model ID": "ID do modelo personalizado",
"Validate": "Validar",
"Model available": "Modelo disponível",
"Connection": "Conexão",
"Test Connection": "Testar conexão",
"Connected": "Conectado",
"Custom Colors": "Cores personalizadas",
"Color E-Ink Mode": "Modo E-Ink colorido",
"Reading Ruler": "Régua de leitura",
"Enable Reading Ruler": "Ativar régua de leitura",
"Lines to Highlight": "Linhas para destacar",
"Ruler Color": "Cor da régua",
"Command Palette": "Paleta de Comandos",
"Search settings and actions...": "Pesquisar definições e ações...",
"No results found for": "Nenhum resultado encontrado para",
"Type to search settings and actions": "Digite para pesquisar definições e ações",
"Recent": "Recente",
"navigate": "navegar",
"select": "selecionar",
"close": "fechar",
"Search Settings": "Pesquisar Definições",
"Page Margins": "Margens da Página",
"AI Provider": "Fornecedor de IA",
"Ollama URL": "URL do Ollama",
"Ollama Model": "Modelo do Ollama",
"AI Gateway Model": "Modelo de AI Gateway",
"Actions": "Ações",
"Navigation": "Navegação",
"Set status for {{count}} book(s)_one": "Definir estado para {{count}} livro",
"Set status for {{count}} book(s)_other": "Definir estado para {{count}} livros",
"Mark as Unread": "Marcar como não lido",
"Mark as Finished": "Marcar como concluído",
"Finished": "Concluído",
"Unread": "Não lido",
"Clear Status": "Limpar estado",
"Status": "Estado",
"Set status for {{count}} book(s)_many": "Definir status para {{count}} livros",
"Loading": "Carregando...",
"Exit Paragraph Mode": "Sair do modo de parágrafo",
"Paragraph Mode": "Modo de parágrafo",
"Embedding Model": "Modelo de incorporação",
"{{count}} book(s) synced_one": "{{count}} livro sincronizado",
"{{count}} book(s) synced_many": "{{count}} livros sincronizados",
"{{count}} book(s) synced_other": "{{count}} livros sincronizados",
"Unable to start RSVP": "Não foi possível iniciar o RSVP",
"RSVP not supported for PDF": "RSVP não suportado para PDF",
"Select Chapter": "Selecionar capítulo",
"Context": "Contexto",
"Ready": "Pronto",
"Chapter Progress": "Progresso do capítulo",
"words": "palavras",
"{{time}} left": "{{time}} restante",
"Reading progress": "Progresso de leitura",
"Skip back 15 words": "Voltar 15 palavras",
"Back 15 words (Shift+Left)": "Voltar 15 palavras (Shift+Esquerda)",
"Pause (Space)": "Pausar (Espaço)",
"Play (Space)": "Reproduzir (Espaço)",
"Skip forward 15 words": "Avançar 15 palavras",
"Forward 15 words (Shift+Right)": "Avançar 15 palavras (Shift+Direita)",
"Decrease speed": "Diminuir velocidade",
"Slower (Left/Down)": "Mais lento (Esquerda/Baixo)",
"Increase speed": "Aumentar velocidade",
"Faster (Right/Up)": "Mais rápido (Direita/Cima)",
"Start RSVP Reading": "Iniciar leitura RSVP",
"Choose where to start reading": "Escolha onde começar a ler",
"From Chapter Start": "Do início do capítulo",
"Start reading from the beginning of the chapter": "Começar a ler do início do capítulo",
"Resume": "Retomar",
"Continue from where you left off": "Continuar de onde parou",
"From Current Page": "Da página atual",
"Start from where you are currently reading": "Começar de onde está lendo no momento",
"From Selection": "Da seleção",
"Speed Reading Mode": "Modo de leitura rápida",
"Scroll left": "Rolar para a esquerda",
"Scroll right": "Rolar para a direita",
"Library Sync Progress": "Progresso de sincronização da biblioteca",
"Back to library": "Voltar à biblioteca",
"Group by...": "Agrupar por...",
"Export as Plain Text": "Exportar como texto simples",
"Export as Markdown": "Exportar como Markdown",
"Show Page Navigation Buttons": "Botões de navegação",
"Page {{number}}": "Página {{number}}",
"highlight": "destaque",
"underline": "sublinhado",
"squiggly": "ondulado",
"red": "vermelho",
"violet": "violeta",
"blue": "azul",
"green": "verde",
"yellow": "amarelo",
"Select {{style}} style": "Selecionar estilo {{style}}",
"Select {{color}} color": "Selecionar cor {{color}}",
"Close Book": "Fechar livro",
"Speed Reading": "Leitura rápida",
"Close Speed Reading": "Fechar leitura rápida",
"Authors": "Autores",
"Books": "Livros",
"Groups": "Grupos",
"Back to TTS Location": "Voltar para a localização do TTS",
"Metadata": "Metadados",
"Image viewer": "Visualizador de imagens",
"Previous Image": "Imagem anterior",
"Next Image": "Próxima imagem",
"Zoomed": "Com zoom",
"Zoom level": "Nível de zoom",
"Table viewer": "Visualizador de tabelas",
"Unable to connect to Readwise. Please check your network connection.": "Não foi possível conectar ao Readwise. Por favor, verifique sua conexão de rede.",
"Invalid Readwise access token": "Token de acesso do Readwise inválido",
"Disconnected from Readwise": "Desconectado do Readwise",
"Never": "Nunca",
"Readwise Settings": "Configurações do Readwise",
"Connected to Readwise": "Conectado ao Readwise",
"Last synced: {{time}}": "Última sincronização: {{time}}",
"Sync Enabled": "Sincronização ativada",
"Disconnect": "Desconectar",
"Connect your Readwise account to sync highlights.": "Conecte sua conta do Readwise para sincronizar os destaques.",
"Get your access token at": "Obtenha seu token de acesso em",
"Access Token": "Token de acesso",
"Paste your Readwise access token": "Cole seu token de acesso do Readwise",
"Config": "Configuração",
"Readwise Sync": "Sincronização com o Readwise",
"Push Highlights": "Enviar destaques",
"Highlights synced to Readwise": "Destaques sincronizados com o Readwise",
"Readwise sync failed: no internet connection": "Sincronização com o Readwise falhou: sem conexão com a internet",
"Readwise sync failed: {{error}}": "Sincronização com o Readwise falhou: {{error}}",
"System Screen Brightness": "Brilho da tela do sistema",
"Page:": "Página:",
"Page: {{number}}": "Página: {{number}}",
"Annotation page number": "Número de página da anotação",
"Translating...": "Traduzindo...",
"Show Battery Percentage": "Mostrar porcentagem da bateria",
"Hide Scrollbar": "Ocultar barra de rolagem",
"Skip to last reading position": "Ir para a última posição de leitura",
"Show context": "Mostrar contexto",
"Hide context": "Ocultar contexto",
"Decrease font size": "Diminuir tamanho da fonte",
"Increase font size": "Aumentar tamanho da fonte",
"Focus": "Foco",
"Theme color": "Cor do tema",
"Import failed": "Falha na importação",
"Available Formatters:": "Formatadores disponíveis:",
"Format date": "Formatar data",
"Markdown block quote (> per line)": "Citação Markdown (> por linha)",
"Newlines to <br>": "Quebras de linha para <br>",
"Change case": "Alterar maiúsculas/minúsculas",
"Trim whitespace": "Remover espaços",
"Truncate to n characters": "Truncar para n caracteres",
"Replace text": "Substituir texto",
"Fallback value": "Valor padrão",
"Get length": "Obter comprimento",
"First/last element": "Primeiro/último elemento",
"Join array": "Juntar array",
"Backup failed: {{error}}": "Falha no backup: {{error}}",
"Select Backup": "Selecionar backup",
"Restore failed: {{error}}": "Falha na restauração: {{error}}",
"Backup & Restore": "Backup e restauração",
"Create a backup of your library or restore from a previous backup. Restoring will merge with your current library.": "Crie um backup da sua biblioteca ou restaure a partir de um backup anterior. A restauração será mesclada com sua biblioteca atual.",
"Backup Library": "Fazer backup da biblioteca",
"Restore Library": "Restaurar biblioteca",
"Creating backup...": "Criando backup...",
"Restoring library...": "Restaurando biblioteca...",
"{{current}} of {{total}} items": "{{current}} de {{total}} itens",
"Backup completed successfully!": "Backup concluído com sucesso!",
"Restore completed successfully!": "Restauração concluída com sucesso!",
"Your library has been saved to the selected location.": "Sua biblioteca foi salva no local selecionado.",
"{{added}} books added, {{updated}} books updated.": "{{added}} livros adicionados, {{updated}} livros atualizados.",
"Operation failed": "Operação falhou",
"Loading library...": "Carregando biblioteca...",
"{{count}} books refreshed_one": "{{count}} livro atualizado",
"{{count}} books refreshed_many": "{{count}} livros atualizados",
"{{count}} books refreshed_other": "{{count}} livros atualizados",
"Failed to refresh metadata": "Falha ao atualizar metadados",
"Refresh Metadata": "Atualizar metadados",
"Keyboard Shortcuts": "Atalhos de teclado",
"View all keyboard shortcuts": "Ver todos os atalhos de teclado",
"Switch Sidebar Tab": "Alternar aba da barra lateral",
"Toggle Notebook": "Mostrar/ocultar caderno",
"Search in Book": "Pesquisar no livro",
"Toggle Scroll Mode": "Alternar modo rolagem",
"Toggle Select Mode": "Alternar modo seleção",
"Toggle Bookmark": "Alternar marcador",
"Toggle Text to Speech": "Alternar texto para fala",
"Play / Pause TTS": "Reproduzir / Pausar TTS",
"Toggle Paragraph Mode": "Alternar modo parágrafo",
"Highlight Selection": "Destacar seleção",
"Underline Selection": "Sublinhar seleção",
"Annotate Selection": "Anotar seleção",
"Search Selection": "Pesquisar seleção",
"Copy Selection": "Copiar seleção",
"Translate Selection": "Traduzir seleção",
"Dictionary Lookup": "Pesquisar no dicionário",
"Wikipedia Lookup": "Pesquisar na Wikipédia",
"Read Aloud Selection": "Ler seleção em voz alta",
"Proofread Selection": "Revisar seleção",
"Open Settings": "Abrir configurações",
"Open Command Palette": "Abrir paleta de comandos",
"Show Keyboard Shortcuts": "Mostrar atalhos de teclado",
"Open Books": "Abrir livros",
"Toggle Fullscreen": "Alternar tela cheia",
"Close Window": "Fechar janela",
"Quit App": "Sair do aplicativo",
"Go Left / Previous Page": "Ir para a esquerda / Página anterior",
"Go Right / Next Page": "Ir para a direita / Próxima página",
"Go Up": "Ir para cima",
"Go Down": "Ir para baixo",
"Previous Chapter": "Capítulo anterior",
"Next Chapter": "Próximo capítulo",
"Scroll Half Page Down": "Rolar meia página para baixo",
"Scroll Half Page Up": "Rolar meia página para cima",
"Save Note": "Salvar nota",
"Single Section Scroll": "Rolagem por seção",
"General": "Geral",
"Text to Speech": "Texto para fala",
"Zoom": "Zoom",
"Window": "Janela",
"Your Bookshelf": "Sua estante",
"TTS": "Leitura em voz alta",
"Media Info": "Info de mídia",
"Update Frequency": "Frequência de atualização",
"Every Sentence": "A cada frase",
"Every Paragraph": "A cada parágrafo",
"Every Chapter": "A cada capítulo",
"TTS Media Info Update Frequency": "Frequência de atualização de info de mídia TTS",
"Select reading speed": "Selecionar velocidade de leitura",
"Drag to seek": "Arraste para procurar",
"Punctuation Delay": "Atraso de pontuação",
"Please confirm that this OPDS connection will be proxied through Readest servers on the web app before continuing.": "Confirme que esta conexão OPDS será encaminhada através dos servidores Readest no aplicativo web antes de continuar.",
"Custom Headers": "Cabeçalhos personalizados",
"Custom Headers (optional)": "Cabeçalhos personalizados (opcional)",
"Add one header per line using \"Header-Name: value\".": "Adicione um cabeçalho por linha usando \"Header-Name: value\".",
"I understand this OPDS connection will be proxied through Readest servers on the web app. If I do not trust Readest with these credentials or headers, I should use the native app instead.": "Entendo que esta conexão OPDS será encaminhada através dos servidores Readest no aplicativo web. Se não confio no Readest com essas credenciais ou cabeçalhos, devo usar o aplicativo nativo.",
"Unable to connect to Hardcover. Please check your network connection.": "Não foi possível conectar ao Hardcover. Verifique sua conexão de rede.",
"Invalid Hardcover API token": "Token de API do Hardcover inválido",
"Disconnected from Hardcover": "Desconectado do Hardcover",
"Hardcover Settings": "Configurações do Hardcover",
"Connected to Hardcover": "Conectado ao Hardcover",
"Connect your Hardcover account to sync reading progress and notes.": "Conecte sua conta Hardcover para sincronizar o progresso de leitura e notas.",
"Get your API token from hardcover.app → Settings → API.": "Obtenha seu token de API em hardcover.app → Configurações → API.",
"API Token": "Token de API",
"Paste your Hardcover API token": "Cole seu token de API do Hardcover",
"Hardcover sync enabled for this book": "Sincronização do Hardcover ativada para este livro",
"Hardcover sync disabled for this book": "Sincronização do Hardcover desativada para este livro",
"Hardcover Sync": "Sincronização do Hardcover",
"Enable for This Book": "Ativar para este livro",
"Push Notes": "Enviar notas",
"Enable Hardcover sync for this book first.": "Ative primeiro a sincronização do Hardcover para este livro.",
"No annotations or excerpts to sync for this book.": "Não há anotações ou trechos para sincronizar neste livro.",
"Configure Hardcover in Settings first.": "Configure o Hardcover nas configurações primeiro.",
"No new Hardcover note changes to sync.": "Não há novas alterações de notas do Hardcover para sincronizar.",
"Hardcover synced: {{inserted}} new, {{updated}} updated, {{skipped}} unchanged": "Hardcover sincronizado: {{inserted}} novos, {{updated}} atualizados, {{skipped}} inalterados",
"Hardcover notes sync failed: {{error}}": "Falha na sincronização de notas do Hardcover: {{error}}",
"Reading progress synced to Hardcover": "Progresso de leitura sincronizado com o Hardcover",
"Hardcover progress sync failed: {{error}}": "Falha na sincronização de progresso do Hardcover: {{error}}",
"ISBN": "ISBN",
"Keep existing source identifier": "Manter o identificador de origem existente",
"Toggle Toolbar": "Alternar barra de ferramentas"
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More