Compare commits

...

1065 Commits

Author SHA1 Message Date
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
Huang Xin f5b686abd9 release: version 0.9.63 (#1550) 2025-07-07 15:07:35 +02:00
Huang Xin 74e1b733a9 layout: dismiss system context menu popup when selecting text on iPad, closes #1485 (#1549) 2025-07-07 14:57:04 +02:00
Huang Xin a9e0090275 i18n: add Thai (th-TH) translations (#1548) 2025-07-07 11:21:41 +02:00
Huang Xin 68d57da9ca perf: speed up opening for large MOBI books, closes #1544 (#1547) 2025-07-07 10:15:54 +02:00
Bhscer 3cef529ebd feat: support deleting only the cloud backup of a book (#1546)
* feat: support delete the cloud storage of a book

* feat: merge to delete function

* fix: change a logic
2025-07-07 09:37:11 +02:00
Huang Xin 85ac399e2c tts: fix some direct text being skipped in tts, closes #1515 (#1543) 2025-07-06 12:13:40 +02:00
Huang Xin e8d09773a2 fix: handling toc links for some mobi books, closes #1525 (#1542) 2025-07-06 08:49:47 +02:00
Huang Xin 23905407ca doc: layout for the download badges (#1541) 2025-07-06 05:42:29 +02:00
Huang Xin 2ab1304b6d doc: update Readme for mobile apps downloads (#1540) 2025-07-06 05:20:30 +02:00
Huang Xin d94236e127 layout: fix grid cover image height in crop mode (#1537)
Support setting arbitrary columns with custom UI css:
```
.bookshelf-items {
  grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}
```
2025-07-05 17:29:33 +02:00
Huang Xin 630025c123 chore: update Android target sdk to 35 (#1534) 2025-07-05 08:49:41 +02:00
Huang Xin 2b73c5a85a perf: lazy loading fonts in fonts list (#1533) 2025-07-05 07:32:22 +02:00
Huang Xin a03f2c585f layout: fix overlay scrollbar with virtualized list, closes #1524 (#1530) 2025-07-04 19:36:13 +02:00
Huang Xin 8a0216dcf8 fix: links in mobi are now properly followed, closes #1503 (#1528) 2025-07-04 07:47:27 +02:00
Huang Xin 59013be586 settings: remove unsupported screen orientation lock on iPad, closes #1520 (#1522) 2025-07-03 13:41:42 +02:00
Huang Xin c6a638dbfd compat: footnote img size, closes #1518 (#1519) 2025-07-02 18:55:09 +02:00
Huang Xin e54440ad80 chore: retry workflow for r2 uploading (#1517) 2025-07-02 17:37:05 +02:00
Huang Xin 446b014f7d chore: upload to r2 after release with retry (#1516) 2025-07-02 17:23:12 +02:00
Huang Xin 9190433ea1 subscription: fix action button in plan card (#1514) 2025-07-02 16:48:32 +02:00
Huang Xin d78d135600 release: version 0.9.62 (#1513) 2025-07-02 15:02:20 +02:00
Huang Xin 04b6c89e58 layout: refine user profile page (#1512) 2025-07-02 13:50:22 +02:00
Huang Xin 8eefba2bee feat: add an option to show/hide original text in translation, also closes #1492 (#1511) 2025-07-02 07:27:05 +02:00
Huang Xin a254139200 layout: extend drag area outward so the scrollbar remains clickable (#1509) 2025-07-01 09:55:09 +02:00
Huang Xin 0514bed5b7 css: fix for legacy epub image dimension, closes #1507 (#1508) 2025-07-01 09:46:27 +02:00
Huang Xin 49978c5e3f layout: add overlay scrollbar for TOC on Android (#1506) 2025-07-01 09:17:18 +02:00
Huang Xin b959bf070c feat: add upgrade to premium option in settings menu (#1505) 2025-07-01 09:15:25 +02:00
Huang Xin 49e6877810 feat: add option to toggle Parallel Reading on/off when viewing multiple books, closes #1496 (#1504) 2025-06-30 19:06:59 +02:00
Huang Xin bb759597e9 shortcuts: add ESC to dismiss search bar, closes #1495 (#1502) 2025-06-30 16:13:43 +02:00
Huang Xin bf0bb80009 api: fix for supabase RLS (#1501) 2025-06-30 15:08:53 +02:00
Huang Xin 5d61a9808f feat: add subscription management for tauri platforms (#1499) 2025-06-30 10:04:57 +02:00
Huang Xin bc36da6b25 feat: add subscription management for web (#1494) 2025-06-29 18:33:36 +02:00
Huang Xin 280cb75ca4 api: cors in middleware (#1493) 2025-06-29 17:00:52 +02:00
Huang Xin d5d0a9abd3 api: add subscription API (#1491) 2025-06-29 14:38:04 +02:00
Huang Xin 9f343992b2 settings: add three new CJK fonts (#1484) 2025-06-27 12:31:01 +02:00
Huang Xin 7ab7058dba refactor: fix fallback cover image for fitted mode (#1483) 2025-06-27 10:28:38 +02:00
Huang Xin c3113ade13 chore: fix uninlined format args warning (#1482) 2025-06-27 10:27:21 +02:00
Huang Xin 7737c05c8f layout: apply custom css also to the library page, tweaks on fitted cover images (#1481) 2025-06-27 10:01:17 +02:00
Huang Xin 4fde9955b2 release: version 0.9.61 (#1479) 2025-06-26 11:27:02 +02:00
Huang Xin 3875c8f239 feat: add an option to show remaining pages in chapter (#1478) 2025-06-26 11:19:30 +02:00
Huang Xin 7bd1b03652 fix: get correct filename when importing txt files on iOS (#1477) 2025-06-26 10:21:55 +02:00
Huang Xin 73878c14e3 fix: EPUB covers occasionally fail to display in library view, closes #1029 (#1476) 2025-06-26 10:03:35 +02:00
Huang Xin bc2c3a2c9a feat: add options to reset settings in the config dialog, closes #1111 (#1475) 2025-06-26 09:59:34 +02:00
Huang Xin 460d37c656 chore: update assetlinks and deeplink for Android (#1474) 2025-06-25 14:47:50 +02:00
Huang Xin fff9e3221e chore: use default production supabase and posthog if not customized, closes #1454 (#1473) 2025-06-25 13:46:48 +02:00
Huang Xin f77fa17cbc bump: update tauri to latest dev branch, closes #1468 (#1471) 2025-06-25 05:36:45 +02:00
Huang Xin d4565f7d60 feat: add an option in the view menu to crop or fit book covers of the library page (#1469) 2025-06-25 03:48:08 +02:00
Huang Xin e8b1976f4f doc: adjust the priority of the readest koplugin for Koreader (#1467) 2025-06-24 08:34:31 +02:00
Huang Xin 6b4bb64885 feat: custom css for the reader UI (#1466) 2025-06-24 08:33:49 +02:00
Huang Xin fc0c42f7db android: fix transparent icon background on Android, closes #1462 (#1464) 2025-06-24 06:54:49 +02:00
Huang Xin 41e5f27d4d layout: view menu now has a maximum width, closes #1459 (#1463)
* refactor: auth callback page

* layout: view menu now has a maximum width, closes #1459
2025-06-24 05:44:03 +02:00
Huang Xin a042b4c739 fix: longer timeout to save changes before reloading page (#1461) 2025-06-24 05:01:46 +02:00
Huang Xin a1c1a9f983 chore: bump opennextjs and wrangler to latest versions (#1460) 2025-06-24 03:22:12 +02:00
Huang Xin 423ae77160 doc: add the Support section in README (#1458) 2025-06-23 12:46:08 +02:00
Huang Xin 05c61a4b1a doc: add donation badge and link with crypto payment (#1457) 2025-06-23 11:37:13 +02:00
Huang Xin ce8f06b7fb chore: add sponsor readest link 2025-06-23 05:03:21 +02:00
Huang Xin f815844577 release: version 0.9.60 (#1452) 2025-06-22 11:24:47 +02:00
Huang Xin 7fe4d38c51 fix: allow inline scripts on Tauri platforms (#1451) 2025-06-22 11:22:39 +02:00
Huang Xin 43edcb4e9e android: dismiss the splash screen and change icon background color in task list (#1450)
* layout: various layout fix on iPad

* android: dismiss the splash screen and change icon background color in task list, closes #1424
2025-06-22 09:10:03 +02:00
Huang Xin e259b29afa fix: disable translation when the primary language is not defined, closes #1443 (#1448) 2025-06-22 07:10:22 +02:00
Huang Xin cd5f57a004 layout: ignore system top/bottom safe insets when there is no header or footer, closes #1442 (#1447) 2025-06-22 06:32:23 +02:00
Huang Xin 8c0cdb0e22 layout: tweaks on layout for iPad (#1446) 2025-06-22 05:55:40 +02:00
初五 c0df9f1cb6 doc: correct spelling 'Themeing' to 'Theming' in README (#1444) 2025-06-22 08:19:21 +08:00
Huang Xin cb1ddaeedb fix: smoother orientation change in iOS, closes #1434 (#1441) 2025-06-21 17:11:45 +02:00
Huang Xin 4447dd7b9a css: fix unintended font size adjust in scrolled mode on iOS, closes #1438 (#1440) 2025-06-21 13:25:46 +02:00
Huang Xin dcb7602837 fix: importing books on iOS at first launch is more reliable now (#1439) 2025-06-21 13:17:24 +02:00
Huang Xin 60e48742fe chore: allow download url for installers (#1437) 2025-06-21 11:13:59 +02:00
Huang Xin dd43569778 chore: download releases using cloudflare cdn (#1436) 2025-06-21 10:36:51 +02:00
Huang Xin 8433dd6950 chore: upload release artifacts to a R2 release bucket (#1435) 2025-06-21 16:24:49 +08:00
Huang Xin 379802f580 release: ready for Google Play release, closes #1001 (#1433) 2025-06-20 16:48:53 +02:00
Huang Xin 2dcb5d7c1e sync: add network timeout of sync to 5 sec (#1432)
* sync: add network timeout of sync to 5 sec

* css: minor tweaks on headings and list
2025-06-20 16:45:10 +02:00
Huang Xin 98870d9f3e release: version 0.9.59 (#1429) 2025-06-19 17:10:14 +02:00
Huang Xin 31aeb2289c settings: more reasonable constraints for top and bottom margins (#1428) 2025-06-19 17:01:20 +02:00
Huang Xin 0f66ecbba1 layout: remove unnecessary inset for header on landscape screen in iOS (#1425) 2025-06-19 12:01:42 +02:00
Huang Xin f0d3c9dd4e fix: transform vw/vh to pixels correctly, closes #1420 (#1421)
* i18n: update translations

* fix: transform vw/vh to pixels correctly, closes #1420
2025-06-19 10:53:58 +02:00
Huang Xin 92aae340d9 settings: unset deprecated margin settings (#1419) 2025-06-18 18:56:41 +02:00
Huang Xin 3cf40039ee release: version 0.9.58 (#1418) 2025-06-18 18:23:09 +02:00
Huang Xin 7ed4937d9d settings: add an option to always show status bar (#1417) 2025-06-18 18:15:55 +02:00
Huang Xin b3593c0365 feat: support split-screen mode on iPad, closes #971 (#1416) 2025-06-18 15:54:46 +02:00
Huang Xin 6235202066 layout: fix issue where sidebars couldn’t be dragged to resize on iPad (#1415) 2025-06-18 15:43:51 +02:00
Huang Xin b3d1085ddf fix: now it's possible to have multiple columns in portrait mode, closes #1369 (#1413) 2025-06-18 14:25:32 +02:00
Huang Xin b2a4ddae60 feat: show annotation create time and various other UI fixes (#1412) 2025-06-18 13:17:18 +02:00
Huang Xin 42f50af27b tts: each book view now has its own tts controller (#1411) 2025-06-18 11:37:02 +02:00
Huang Xin 07f74d8858 settings: individually adjust top, bottom, left, and right margins on the reader page (#1410) 2025-06-18 10:55:24 +02:00
Huang Xin 9477789db1 layout: apply responsive safe area insets to the reader page, closes #1067 and closes #1212 (#1408)
This also fixes layout glitches when showing status bar on devices without display cutouts
2025-06-17 03:36:23 +02:00
Huang Xin 8a7d0e1b0d fix: annotation tools now works when TTS is enabled, closes #1403 (#1406) 2025-06-16 08:53:55 +02:00
Huang Xin 261ce95ed1 feat: add keyboard shortcut t to toggle TTS (#1405) 2025-06-16 08:50:10 +02:00
Huang Xin c5a3b44cbf chore: add NEXT_PUBLIC_API_BASE_URL in example env file (#1404) 2025-06-16 06:02:50 +02:00
Huang Xin ed68d25b15 fix: restore full view settings when reopening book (#1400) 2025-06-15 16:07:51 +02:00
Huang Xin f7f8872a13 tts: translation also when TTS is played in the background, closes #1383 (#1399) 2025-06-15 09:07:22 +02:00
Huang Xin be9802a936 release: version 0.9.57 (#1395) 2025-06-14 15:42:08 +02:00
Huang Xin 84328dcfb2 hotfix: resolve compatibility issues with Android Text-to-Speech API (#1394) 2025-06-14 15:39:12 +02:00
Huang Xin 89d48c72b0 release: version 0.9.56 (#1391) 2025-06-13 17:35:38 +02:00
Huang Xin 467e80cd4b fix: various fixes on text selector in TTS mode and normal image height (#1390) 2025-06-13 17:28:21 +02:00
Huang Xin 20955ec294 chore: handle client uncaught exceptions and show error message (#1389) 2025-06-13 15:24:24 +02:00
James Sizeland 3cae183f51 feat: add syntax highlighting (#1386)
* add highlightjs

* add github light and dark theme

* inject style classes

* fix typo

* remove conflicting style overrides

* add highlightjs function and language list

* add language select setting

* add language select input

* add watcher to rerender page on changes to language select

* lockfile update

* rename highlightCode variables

* reorder code languages alphabetically

* copy translation style for highlight selector

* move code highlighting below theme color section

* move highlighting toggle logic into settings component

* add conditional statement to docLoadHandler manageSyntaxHighlighting

* reorder imports

* switch to media query for dark mode

* combine useEffect callbacks for code highlighting

* add feature line about code highlighting

* fix table tabbing
2025-06-13 14:40:18 +02:00
Huang Xin 99319ab4d1 fix: TTS now properly loads the next chapter in the background, closes #1382 (#1388) 2025-06-13 13:54:17 +02:00
Huang Xin 658969e97a feat: support native tts engine on Android (#1387) 2025-06-12 17:56:14 +02:00
James Sizeland 28c6c1ec58 css: add more aggressive overrides for background and text colour (#1384)
* add more aggressive overrides for background and text colour

* reduce styles changes
2025-06-12 14:24:50 +02:00
James Sizeland d8cc220c18 chore: add vscode settings to include inlayhints (#1385) 2025-06-12 14:22:49 +02:00
Huang Xin 97d7eb659c bump: sync with upstream foliate-js (#1381) 2025-06-11 05:11:06 +02:00
Ahmed 9766ec0125 i18n: improve some Arabic strings in translation.json (#1380) 2025-06-11 03:05:49 +02:00
Huang Xin e46d01448b css: handle inline image height (#1379) 2025-06-10 08:43:00 +02:00
Huang Xin bb8bf99b40 Also transform CSS for azw3 files (#1378) 2025-06-10 06:39:15 +02:00
Huang Xin f8ac30adf1 tts: add native tts plugin for Android (#1376) 2025-06-09 16:54:12 +02:00
Huang Xin 69d418aa61 perf: optimize toc list view for very large toc list, closes #386 (#1370) 2025-06-08 15:01:34 +02:00
Huang Xin 95af3bd3d1 release: version 0.9.55 (#1366)
* release: version 0.9.55

* layout: fix drag handler for multiple dialog instances
2025-06-07 07:55:36 +02:00
Huang Xin 5bdc29fe84 perf: optimize by removing unnecessary animations on Android, closes #1360 (#1365) 2025-06-07 06:53:53 +02:00
Huang Xin 56f4b275f4 translator: toast for Daily Quota Exceeded error (#1363) 2025-06-06 16:24:14 +02:00
Huang Xin 00b46dd8bb bump: upgrade next.js to latest version (#1362) 2025-06-06 15:40:33 +02:00
Huang Xin 8ce89ca8f6 bump: upgrade supabase.js to latest version (#1361) 2025-06-06 14:37:29 +02:00
Huang Xin 648d9ec260 css: unset justify text align when overriding layout, closes #1338 (#1358) 2025-06-06 12:08:53 +02:00
Huang Xin ebe1c10c84 sync: also update deleted notes in synchronization, closes #1356 (#1357) 2025-06-06 11:47:26 +02:00
Huang Xin f2309ef496 release: version 0.9.53 (#1351) 2025-06-05 17:42:22 +02:00
Huang Xin 8d71593f39 fix: exit select mode when all books are deleted, closes #1347 (#1350) 2025-06-05 17:26:55 +02:00
Huang Xin 09e3c30a2a feat: add daily translation quota of DeepL API for more sustainable service (#1349) 2025-06-05 16:58:07 +02:00
Huang Xin eee4cbeaca fix: avoid additional click after books is downloaded before opening (#1346) 2025-06-05 11:43:46 +02:00
Huang Xin 00deca5029 bump: upgrade opennext and wrangler to latest versions (#1345) 2025-06-05 10:46:52 +02:00
Huang Xin c7c20fec55 epub: last resort to get the first image in manifest as book cover (#1343) 2025-06-05 08:40:48 +02:00
Huang Xin 57e22dc7b6 layout: use system select widget for language selection, closes #1339 (#1342) 2025-06-05 08:19:24 +02:00
Huang Xin debd60fb70 css: inline image only as direct children of p and span, closes #1340 (#1341) 2025-06-05 07:47:56 +02:00
Huang Xin dfa17c1c0b css: auto height for single images in anchor (#1337) 2025-06-04 20:08:16 +02:00
Huang Xin 2a26f8b04a fix: trigger library update for the books counter after importing books (#1336) 2025-06-04 19:02:49 +02:00
Huang Xin db955d2c8c feat: add an option to override book fg/bg color, closes #1328 (#1335) 2025-06-04 18:58:53 +02:00
Huang Xin 51602a77fb tts: disable media session controls to keep alive tts (#1333) 2025-06-04 08:17:33 +02:00
Huang Xin 48da5ab546 fix: update current bookshelf after importing and deleting books (#1331) 2025-06-03 19:33:23 +02:00
Huang Xin 363b98dd3b release: version 0.9.52 (#1327) 2025-06-03 15:49:04 +02:00
Huang Xin 43532a0ee8 feat: add an option to show remaining in minutes of the current chapter, closes #406 (#1326) 2025-06-03 15:37:55 +02:00
Huang Xin 03b2af1f97 chore: bump pdf.js to latest release of version 4 (#1325) 2025-06-03 13:22:52 +02:00
Huang Xin 3f8d03ae28 sync: add sync status menu item in view menu, closes #844 (#1324) 2025-06-03 11:43:58 +02:00
Huang Xin 146a71fdef font: load CJK fonts only in CJK env or the book has CJK languages, closes #1298 (#1323) 2025-06-03 08:55:40 +02:00
Huang Xin 734e22d92c layout: notebook layout tweaks (#1319) 2025-06-02 17:27:02 +02:00
Huang Xin a77986c0e6 feat: add search functionality to the notebook (#1318) 2025-06-02 16:03:55 +02:00
Huang Xin 4e7f9c49b0 layout: render book description as html in book details, closes #1316 (#1317) 2025-06-02 14:25:51 +02:00
Huang Xin c51c95b883 feat: support note taking with markdown, closes #1097 (#1315) 2025-06-02 11:35:09 +02:00
Huang Xin 62081bebfd fix: update current bookshelf items when library is updated (#1314) 2025-06-02 09:57:11 +02:00
Huang Xin 15394d17d8 feat: show current books count in search bar, closes #1310 (#1312) 2025-06-02 09:31:35 +02:00
Huang Xin 5d1deadc1e fix: defers rendering all component until after hydration for Tauri platforms, closes #1301 (#1311) 2025-06-02 08:25:08 +02:00
Huang Xin b497ddacac css: add margin for div only when overriding layout, closes #1286 (#1309) 2025-06-02 07:59:58 +02:00
Huang Xin a9965fd52c config: add an option to sort TOC by page number, closes #1304 (#1308) 2025-06-02 07:23:59 +02:00
Huang Xin 87d610bb62 revert: some browsers may report wrong pixel density, closes #1305 (#1306)
This reverts commit 6e0cc38aa7ca726e251c16e453922fcd637cee49.
2025-06-02 06:19:13 +02:00
Huang Xin dbc4651141 chore: parse webkit version on linux (#1299) 2025-06-01 04:57:53 +02:00
Huang Xin dad2dfd078 i18n: update translations (#1297) 2025-05-31 18:58:43 +02:00
Huang Xin 1fe188814d release: version 0.9.51 (#1296) 2025-05-31 18:33:21 +02:00
Huang Xin 6ec3a5b332 feat: add an option to enable JavaScript in EPUB, closes #1278 (#1295) 2025-05-31 18:25:25 +02:00
Huang Xin 1acba2e08c fix: notebook now won't prevent pagination, closes #1285 (#1294) 2025-05-31 15:02:36 +02:00
Huang Xin 32f9346f84 tts: more robust way to save last speaking location for tts (#1293) 2025-05-31 13:34:35 +02:00
Huang Xin 69c503026a bump: catch up foliate-js upstream (#1292) 2025-05-31 13:31:27 +02:00
Huang Xin 84fc4cec5e tts: read from last read sentence in tts (#1291) 2025-05-31 10:53:36 +02:00
Huang Xin 5c9c11fafd translator: disable translator if the system language is the same with the book language (#1290)
Closes #1288
2025-05-31 09:34:52 +02:00
Huang Xin 77fa57438e tts: show speaking sentence and chapter info in tts media session (#1289) 2025-05-31 09:21:17 +02:00
Huang Xin e4d217f3aa config: add theme mode options in the library page (#1283) 2025-05-30 09:10:48 +02:00
Huang Xin c7a583c53a translator: lazy load translation observer (#1282) 2025-05-30 09:08:45 +02:00
Huang Xin 6c86917098 translator: add daily translation quota for deepl (#1275) 2025-05-29 19:24:09 +02:00
Huang Xin 7c21f48d68 layout: hide the header bar only on mobile platforms when translation is enabled (#1274) 2025-05-29 10:31:02 +02:00
Huang Xin 5820191c26 translator: also translate table of contents (#1273) 2025-05-29 10:08:01 +02:00
Huang Xin b37a804192 css: enhanced compatibility with the text-indent CSS property, closes #1267 (#1271) 2025-05-29 08:53:58 +02:00
Huang Xin ebdfc39ef6 release: version 0.9.50 (#1264) 2025-05-28 17:05:02 +02:00
Huang Xin 9f0d8b5c12 tts: select voice in bilingual TTS mode (#1263) 2025-05-28 16:59:45 +02:00
Huang Xin a267671671 layout: more responsive layout for the header in settings dialog (#1257) 2025-05-28 09:28:51 +02:00
Huang Xin aa62ebd3f0 css: unchange color for anchor children, unchange only image dimension in span, closes #1251 and #1252 (#1256) 2025-05-28 08:04:09 +02:00
Huang Xin cc85e5c304 release: version 0.9.49 (#1247) 2025-05-27 14:47:09 +02:00
Huang Xin b0cc0b6f1a layout: better organized panels in settings dialog (#1246) 2025-05-27 14:37:32 +02:00
Huang Xin 6b033f7509 translator: post-process translated text for punctuation spacing (#1245) 2025-05-27 14:32:25 +02:00
Huang Xin 5c0670031a fix: use updated library when dropfile to import on web browser (#1244) 2025-05-26 16:33:18 +02:00
Huang Xin 35735cd931 fix: skip speech when the text is empty at the end of some chapters, closes #1231 (#1243) 2025-05-26 16:03:43 +02:00
Huang Xin 699a01c78f feat: support full book translation to bilingual books, closes #398 (#1240) 2025-05-26 12:23:33 +02:00
Huang Xin 033e161455 layout: overlay the footer of the translator popup and less sensitive page flip with mouse wheel (#1238)
* layout: overlay the footer of the translator popup

* fix: less sensitive page flip with mouse wheel, addresses #1165
2025-05-25 09:32:00 +02:00
Huang Xin e6428656c2 fix: select filtered books when activating select all (#1237) 2025-05-25 08:02:34 +02:00
Huang Xin 68c3c45da3 feat: add an option to opt-out telemetry (#1236) 2025-05-25 07:48:57 +02:00
Huang Xin 36e87d4eb6 layout: display full publisher field in book details, closes #1224 (#1234) 2025-05-24 07:14:22 +02:00
Huang Xin 7f5059a8ea tts: always infer language code from script in bilingual TTS (#1233) 2025-05-24 07:01:41 +02:00
Huang Xin 8dc04f4095 feat: add bilingual TTS support for bilingual books, closes #1226 (#1230) 2025-05-23 18:18:24 +02:00
Huang Xin 6a48f3feb4 fix: use external browsers to open links in epub file, closes #1211 (#1228) 2025-05-23 08:15:57 +02:00
Huang Xin facf5fba75 fix: reorder icons in the ico file for Windows, closes #1175 (#1227) 2025-05-22 16:47:21 +02:00
Huang Xin 9700942e24 fix: transient navigation bar should work now for Android 8-15, closes #1199 (#1225) 2025-05-22 16:12:59 +02:00
Huang Xin e238b49fbf feat: add an option to invert image color in dark mode (#1223) 2025-05-22 10:38:09 +02:00
Huang Xin 32dfadf182 doc: update screenshots (#1222) 2025-05-22 09:34:16 +02:00
Huang Xin 66744108e2 css: unset link color in footnotes in dark mode for safari (#1221) 2025-05-22 09:09:02 +02:00
Huang Xin 401f28847c fix: add location only when toc item is at the same level as the section (#1220) 2025-05-22 08:08:52 +02:00
Huang Xin 9674b45cf0 layout: align text end for select labels on safari (#1219) 2025-05-22 07:03:10 +02:00
Huang Xin a4bc88d305 feat: add azure and google translator providers, closes #1135 and closes #1215 (#1218) 2025-05-21 17:25:00 +02:00
Huang Xin b6b8b17760 fix: normalize input text by removing newlines to prevent translation glitches (#1210) 2025-05-21 05:26:20 +02:00
Huang Xin 14810d6737 feat: add select all button in select mode, closes #1202 (#1209) 2025-05-20 16:58:04 +02:00
Huang Xin ed6c92a65a css: don't override body background, closes #1206 (#1208)
Revisit #1151.
2025-05-20 15:11:36 +02:00
Huang Xin 20d7a1185e layout: grouping modal now should stay on top of the header bar (#1207) 2025-05-20 14:12:17 +02:00
Huang Xin 32bcfda9ad fix: reimporting books will update the import time, being consistent with update time, closes #1200 (#1203) 2025-05-20 04:40:41 +02:00
Huang Xin def157cacb release: version 0.9.43 (#1196) 2025-05-19 16:51:34 +02:00
Huang Xin 7c464b9a8d feat: add prev/next section buttons in footer bar, closes #1125 (#1195) 2025-05-19 16:40:11 +02:00
Huang Xin 90f3512ae2 feat: add scrolling overlap in pixels option to paginate in scrolled mode (#1194) 2025-05-19 15:21:06 +02:00
Huang Xin 12d93ba749 fix: adjust scroll offset to account for header/footer bars when paginating in scroll mode, closes #1181 (#1193) 2025-05-19 10:34:05 +02:00
Huang Xin 554d786105 fix: update library in store when deleting book in bookshelf, closes #1178 (#1191) 2025-05-19 08:31:25 +02:00
Huang Xin eb71c59524 chore: config wrangler before deployment in Cloudflare (#1189) 2025-05-19 07:55:11 +02:00
Huang Xin 93e81ee05b release: remove deprecated MSI installer, closes #1174 (#1187) 2025-05-19 03:29:44 +02:00
Huang Xin b83972e366 refactor: use translator hook to support more translator providers (#1186) 2025-05-18 18:35:37 +02:00
Huang Xin 967536aa23 refactor: update wrangler config (#1185) 2025-05-18 17:52:50 +02:00
Huang Xin 4523437e34 refactor: add kv cache for translation backend (#1184) 2025-05-18 17:16:44 +02:00
Huang Xin e49dd4accb feat: show cloud backup status for each book on mobile and desktop, closes #1167 (#1173) 2025-05-17 17:02:42 +02:00
Huang Xin b7c1f5703c fix: less sensitive magic trackpad and mouse when flipping page, closes #1165 (#1172) 2025-05-17 08:56:22 +02:00
Huang Xin 5373b67aae css: get rid of most overriding for background color, closes #1162 (#1164) 2025-05-16 08:23:34 +02:00
Huang Xin ddc9673260 css: compat for background colors in chapter headers of Feedbooks eBooks (#1163) 2025-05-16 03:29:07 +02:00
Huang Xin 16b0821eab i18n: add translations of Nederlands (#1161) 2025-05-15 18:32:38 +02:00
Huang Xin 93876a73cc layout: responsive translator popup, also closes #1157 (#1160) 2025-05-15 18:19:32 +02:00
Huang Xin 048867e595 settings: disable spell check in color input (#1159) 2025-05-15 05:33:35 +02:00
Huang Xin 602be376a1 css: include additional weight variants for built-in fonts (#1158) 2025-05-15 05:04:16 +02:00
Huang Xin c52ae43cd9 settings: avoid horizontal margin default to zero, fixes #1151 (#1155) 2025-05-14 15:25:32 +02:00
Huang Xin 348d743e82 css: styling adjustments for better compatibility with Gutenberg eBooks (#1154)
This also closes #1153, #1148, #1147 and the css problem in #1151.
2025-05-14 14:55:07 +02:00
Huang Xin c7e495c379 settings: keep screen awake is disabled by default, closes #1145 (#1149)
* layout: hint info now takes up full width in scrolled mode

* settings: keep screen awake is disabled by default, closes #1145
2025-05-14 11:11:32 +02:00
Huang Xin e368076cac chore: update bundleVersion for macOS AppStore build (#1146) 2025-05-14 03:45:00 +02:00
Huang Xin 382e0ca3c6 release: version 0.9.41 (#1143) 2025-05-13 14:17:01 +02:00
Huang Xin d96fb32bcf fix: apply layout styles to div tag, closes #1130 (#1142) 2025-05-13 13:48:21 +02:00
Huang Xin 4779e2638f fix: disable updater for non-appimage app on linux, closes #1129 (#1141) 2025-05-13 12:50:40 +02:00
Huang Xin d094ba9916 chore: cache avatar image for offline usage (#1140) 2025-05-13 10:42:00 +02:00
Huang Xin e4ba0c302e fix: segment txt with paragraph count if no chapter titles are parsed, closes #1134 (#1139) 2025-05-13 10:21:47 +02:00
Huang Xin 0150177a9d chore: bump tauri to version 2.5.1 (#1138) 2025-05-13 09:30:34 +02:00
Huang Xin 74e32d47b0 release: add linux arch armhf (#1133) 2025-05-13 14:57:27 +08:00
Huang Xin 2dd7cf54e6 refactor: use text selector hook in annotator, closes #1020 (#1131) 2025-05-12 18:00:45 +02:00
Huang Xin a5cbfe97db fix: replace background when attribute changed, closes #1124 (#1126) 2025-05-11 17:07:17 +02:00
Huang Xin da49526f4c fix: now auto orientation follows system settings, closes #1093 and closes #1098 (#1122) 2025-05-11 14:57:05 +02:00
Huang Xin 2e46bc1627 css: get rid of hardcoded font color only when overriding font, closes #1095 (#1120) 2025-05-11 14:34:51 +02:00
Huang Xin 7e542e8694 fix: reorganize TTS control view hierarchy, closes #1080 (#1119) 2025-05-11 12:06:15 +02:00
Huang Xin 2a624ef57a css: only override background color in dark mode, closes #1066 (#1117) 2025-05-11 09:33:03 +02:00
Huang Xin 60ae0c9ac3 feat: show book file size in book details (#1114) 2025-05-10 18:28:08 +02:00
Huang Xin 110b4b37cd ui: various UI fixes and enhancements on mobile platforms (#1113) 2025-05-10 18:18:15 +02:00
Huang Xin f0edbf14a9 fix: padding top of the drag handler with the cutouts, closes #1101 (#1110) 2025-05-10 08:27:40 +02:00
Huang Xin 20669a9cb3 fix: show updating status in the about window, closes #1079 (#1109) 2025-05-10 08:00:25 +02:00
Huang Xin 3756bec66c css: special case for align center and zero text indent (#1105) 2025-05-09 14:40:55 +02:00
Huang Xin 3e1d03dc17 css: override text align and fix hardcoded text intent (#1104) 2025-05-09 14:20:38 +02:00
Huang Xin 4aebbf679f fix: various on styles of UI and footnote visibility (#1099)
* fix: footnote now should be hidden in srcdoc iframes

* fix: eliminate white flash on startup when using dark mode

* feat: rescale UI size with pixel density
2025-05-08 18:21:31 +02:00
Huang Xin 0a562d90ac fix: maintain library state across reader/library navigation, closes #1072 (#1096) 2025-05-08 09:26:58 +02:00
Huang Xin e91a39e8b6 release: version 0.9.40 (#1092) 2025-05-07 20:03:58 +02:00
Huang Xin 2006baac4b revert: unbreak style overriding, closes #1058 and closes #1075 (#1091) 2025-05-07 19:56:14 +02:00
Huang Xin 0d4f61f08a compat: fix insane img dimension might cause layout miscalculation, closes #1073 (#1090) 2025-05-07 18:33:13 +02:00
Huang Xin 0b5f0ede3b fix: close action bar when the footbar is dismissed, closes #1064 (#1086) 2025-05-07 14:44:17 +02:00
Huang Xin 99a146525f fix: transient navigation bar in Android 9, closes #1059 (#1085) 2025-05-07 14:11:46 +02:00
Huang Xin 6080f9e0f3 fix: revert to unlock screen orientation for library page, closes #1063 (#1084) 2025-05-07 13:50:40 +02:00
Huang Xin 6b3d41a4b8 fix: styling links and also the content of links, closes #1057 (#1083) 2025-05-07 12:46:28 +02:00
Huang Xin e403c009c2 fix: avoid glitches when expanding toc sub items, closes #1033 (#1081) 2025-05-07 12:22:42 +02:00
Huang Xin 14bf2bcf8f fix: segment separator now should be more than 8 dash, closes #1056 (#1077) 2025-05-07 09:58:30 +02:00
Huang Xin 7f66af71c8 fix: dialog drag handler layout, closes #1036 (#1076) 2025-05-07 09:27:20 +02:00
Huang Xin cbab201138 doc: format issue templates (#1071) 2025-05-07 06:04:20 +02:00
Huang Xin 0f47d6d393 release: version 0.9.39 (#1055) 2025-05-06 18:58:43 +02:00
Huang Xin 38101cb76d fix: temporarily disable font name with style for windows (#1054) 2025-05-06 18:29:27 +02:00
Huang Xin 8f0982ae33 fix: replace bg color only for non-default theme color, closes #1049 (#1053) 2025-05-06 18:16:00 +02:00
Huang Xin 1c015f5973 feat: add option to open last book on start, closes #328 (#1052) 2025-05-06 17:00:57 +02:00
Huang Xin 4c1af671bb fix: use separate compact margin and gap when header and footer are dismissed, closes #734 (#1047) 2025-05-06 12:38:04 +02:00
Huang Xin b4cda00a91 fix: don't scroll when selection is in current page in TTS, closes #863 (#1046) 2025-05-06 11:09:50 +02:00
Huang Xin c326ad402d fix: calculate vw/vh size from iframe viewport, closes #1027 (#1045) 2025-05-06 09:32:01 +02:00
Huang Xin e03636e0a1 fix: expanding clickable region of TOC expander icons, closes #1033 (#1044) 2025-05-06 06:45:51 +02:00
Huang Xin 9669f1272d fix: more robust txt parser, closes #1042 (#1043)
* refactor: reuse BookCover component in BookDetail dialog

* fix: more robust txt parser, closes #1042
2025-05-06 06:28:25 +02:00
Huang Xin 4094fd86ff fix: padding drag handler on Android, closes #1036 (#1039)
* refactor: load default icon when avatar image fails to load

* fix: padding drag handler on Android, closes #1036
2025-05-05 17:42:57 +02:00
Huang Xin 27df89e261 fix: override text-indent when overriding book layout, closes #1026 (#1038) 2025-05-05 11:58:49 +02:00
Huang Xin ddcee6b3df fix: TTS timeout options should popup now in iOS (#1037) 2025-05-05 11:43:10 +02:00
Huang Xin 5e04f6ae03 feat: support locking screen orientation, closes #860 (#1034) 2025-05-05 10:55:50 +02:00
Huang Xin 6299ea09b7 fix: escape special characters when converting from txt to epub, closes #1018 (#1024) 2025-05-04 13:46:08 +02:00
Huang Xin 4f6f45fe8a fix: don't preview font style for system fonts on Linux, closes #1015 (#1023) 2025-05-04 12:23:01 +02:00
Huang Xin 6b290f09f5 refactor: unify hooks for pagination and continuous scroll (#1021) 2025-05-04 10:58:44 +02:00
Huang Xin c9e08f2c01 fix: more robust continuous scroll, closes #993 (#1017) 2025-05-03 12:07:32 +02:00
Huang Xin 8167f27156 feat: add location info for each entry in table of contents (#1016) 2025-05-02 15:08:20 +02:00
Huang Xin 77c7176526 fix: volume retained when app is in background for iOS (#1014) 2025-05-02 11:15:42 +02:00
Huang Xin a8d657414d fix: more robust txt parser (#1005) 2025-04-30 18:01:47 +02:00
Huang Xin ed368e1205 fix: skip rt elements in annotation and search for Japanese books, closes #904 (#1004) 2025-04-30 11:36:52 +02:00
Huang Xin 7de1bdf824 fix: more robust method to detect language for TTS (#1003) 2025-04-30 09:36:51 +02:00
Huang Xin 141c502c76 fix: handle full CJK Unified Ideographs in search terms, closes #989 (#1002) 2025-04-30 08:52:19 +02:00
Huang Xin b1ea729a54 fix: also overriding anchor color when overriding font in dark mode, closes #995 (#1000) 2025-04-30 06:19:32 +02:00
Huang Xin d3eff19ab9 fix: filter out some non-free fonts on Android and Linux, closes #994 (#999) 2025-04-29 20:02:54 +02:00
Huang Xin 59f0cede39 fix: import system fonts list on Android (#998)
Note that the system fonts might not be available in Android webview
2025-04-29 19:14:03 +02:00
Huang Xin 946d17882b fix: reactivating volume keys interception when resumed from background on iOS (#997) 2025-04-29 18:39:36 +02:00
Huang Xin f9adf789d7 release: version 0.9.38 (#986) 2025-04-28 18:24:29 +02:00
Huang Xin efb8f70d01 fix: inherit book fonts for popup footnotes (#985) 2025-04-28 18:16:56 +02:00
Huang Xin e235cb98d2 fix: intercept the Back key to dismiss popup dialogs on Android, closes #636 (#983) 2025-04-28 16:57:15 +02:00
Huang Xin 4275508ccd feat: add volume keys for page turning, closes #471 (#982) 2025-04-28 12:36:24 +02:00
Huang Xin a424ae8b15 feat: retrieve system fonts on iOS and Android and show font weight variants, closes #949 and closes #557 (#976) 2025-04-26 17:37:04 +02:00
Huang Xin 9303ec8c5f feat: add primary color input in theme editor, closes #963 (#970) 2025-04-26 09:58:20 +02:00
Huang Xin 98faed320a feat: add more English voices for all en locales, closes #966 (#969) 2025-04-26 09:00:09 +02:00
Huang Xin 5bbdc70420 fix: preserve selection anchor when spanning paginated content, closes #873 (#968) 2025-04-26 07:45:51 +02:00
Huang Xin de21182240 fix: don't panic on plugin log initialization error, closes #953 (#961) 2025-04-25 14:42:57 +02:00
Huang Xin 4ae35992a1 compat: auto hide navigation bar also for Android version below 11 (#960) 2025-04-25 10:56:36 +02:00
Huang Xin b91d7b7a61 release: version 0.9.37 (#957) 2025-04-24 21:14:57 +02:00
Huang Xin 7c0d9bf375 fix: popup footnotes for anchors without epub namespace, closes #948 (#956) 2025-04-24 21:03:05 +02:00
Huang Xin ea8ab91ed3 feat: add list view for the bookshelf, closes #542 (#955) 2025-04-24 19:53:09 +02:00
Huang Xin efd415ece2 fix: dismiss status bar when resumed from background on Android (#952) 2025-04-24 11:12:10 +02:00
Huang Xin ec86d68b80 fix: check xdg-mime before registering deeplink in Linux, closes #475 (#951) 2025-04-24 16:19:14 +08:00
Huang Xin 172ab382bc fix: query status bar height on Android, closes #943 (#947) 2025-04-23 14:01:37 +02:00
Huang Xin ad551a04a1 feat: add description from metadata in book details, closes #913 (#946) 2025-04-22 19:01:43 +02:00
Huang Xin 4dc943d23e fix: tts now fallbacks to metadata language of the book, closes #916 (#945) 2025-04-22 18:12:14 +02:00
Huang Xin ee93885c04 fix: sync custom themes from global settings to localstorage, closes #917 (#944) 2025-04-22 14:52:46 +02:00
Huang Xin 14c032aaff feat: add global keyboard shortcut to toggle fullscreen with F11, closes #933 (#942) 2025-04-22 14:13:52 +02:00
Huang Xin 2f619ca745 fix: open book even the library is empty, closes #937 (#941) 2025-04-22 13:56:07 +02:00
Huang Xin 8979827cf5 fix: compat language code for api versions (#940) 2025-04-22 12:38:07 +02:00
Huang Xin ae16eeffa7 fix: prevent scrollToAnchor on focus outside content container, closes #906 (#928) 2025-04-21 14:57:01 +02:00
Huang Xin 8e96ef3e5d fix: hide navigation bar on reader page on Android 11, closes #921 (#927) 2025-04-21 14:49:16 +02:00
Huang Xin 38e24da968 fix: support v1 and v2 of translate API (#919) 2025-04-20 12:30:25 +08:00
Huang Xin 7371efe1d1 release: version 0.9.36 (#915) 2025-04-19 18:07:45 +02:00
Huang Xin 3cb37bca5d feat: add GuanKiapTsingKhai-T in the CJK fonts list, closes #884 (#914) 2025-04-19 18:00:35 +02:00
Huang Xin b9fa204eda fix: show system navigation bar by swiping up from bottom on Android, closes #592 (#912) 2025-04-19 17:02:17 +02:00
Huang Xin cf66665096 feat: immersive UI in reader page on iOS and Android, closes #886 and closes #864 (#911) 2025-04-19 16:43:39 +02:00
Huang Xin 759779a98d fix: links in about window is now clickable in apps (#902) 2025-04-17 11:17:07 +02:00
Huang Xin 68409db8a0 compat: more accessible iframes to support LingKuma and Immersive Translate extension, closes #889 (#901) 2025-04-17 10:36:04 +02:00
Huang Xin 46f0e8e7f6 feat: open files with readest from file manager on iOS (#898) 2025-04-16 17:36:11 +02:00
davimed 6260168caa Fix filename with quotes (#897)
* Escape double quotes in filenames

* Format code
2025-04-16 17:34:15 +02:00
Huang Xin a8430a7be1 feat: open files with readest from file manager on Android, closes #865 (#895) 2025-04-16 07:04:30 +02:00
Huang Xin 7bfaa38746 feat: add download/upload buttons in book detail dialogs (#891) 2025-04-15 06:19:29 +02:00
Huang Xin c5b2feda48 release: version 0.9.35 (#888) 2025-04-14 17:50:39 +02:00
Huang Xin 59f875f590 feat: add books sorting by title and author in the library page, closes #540 (#887) 2025-04-14 17:38:41 +02:00
Huang Xin 8efad90932 feat: in-app updater for Android (#885) 2025-04-14 14:21:58 +02:00
Huang Xin 5c23642ac0 chore: generate Android package signature and download url in update file 2025-04-13 23:59:56 +08:00
Huang Xin ee6500cecb fix: books without cover images now can be synced across devices (#878) 2025-04-13 10:47:50 +02:00
Huang Xin f004d7b3ea release: version 0.9.33 (#875) 2025-04-13 02:31:13 +08:00
Huang Xin f7d53508a6 refactor: new updater dialog (#874) 2025-04-13 02:06:14 +08:00
Huang Xin 53e7f2526c fix: window maximized and fullscreen now don't conflict with each other (#872) 2025-04-12 13:42:36 +02:00
Huang Xin 8f0e2d1642 chore: show webview version info in the about window (#869) 2025-04-12 16:35:54 +08:00
Huang Xin c807f0ccc8 refactor: OAuth flow is now handled via ASWebAuthenticationSession on macOS (#866) 2025-04-12 12:49:41 +08:00
Huang Xin 6ba15319a8 fix: reverse punctuation transform when highlighting (#862) 2025-04-11 06:30:08 +02:00
Huang Xin 3ea3a50baa fix: handle file basename from content provider uri (#861) 2025-04-11 05:18:12 +02:00
Huang Xin ccd467ebcf feat: support separate header/footer visibility for paginated and scrolled modes (#859) 2025-04-11 03:40:26 +02:00
Huang Xin fe25c3e995 feat: support native sign-in-with-apple on macOS (#856) 2025-04-10 14:49:11 +02:00
Huang Xin d4af2d3ef5 feat: also add sans-serif CJK fonts (#853) 2025-04-09 16:03:24 +02:00
Huang Xin 6ff1edb67c fix: no padding top for bookmark ribbon (#851) 2025-04-09 13:03:23 +02:00
Huang Xin 3d2847e427 fix: RTL layout for the bottom configuration panel, closes #849 (#850) 2025-04-09 10:47:15 +02:00
Huang Xin ff4d8af054 release: version 0.9.32 (#848) 2025-04-09 06:01:55 +02:00
Huang Xin 612302f42f feat: add LXGW WenKai TC in CJK fonts list (#847) 2025-04-09 05:57:06 +02:00
Huang Xin a26607a154 fix: don't inline the font menu if more options are available (#846) 2025-04-09 05:32:24 +02:00
Huang Xin 939c7049ed fix: position the underline and squiggly highlight decoration at the middle between text lines (#845) 2025-04-09 05:26:22 +02:00
Huang Xin 0ead07e704 fix: don't reset all font-size and font color when override book style (#842) 2025-04-09 01:55:36 +02:00
Huang Xin f4908c4536 release: version 0.9.31 (#839) 2025-04-08 15:54:34 +02:00
Huang Xin 37951c2ebf feat: add book metadata search in the bookshelf, closes #100 (#838) 2025-04-08 15:37:18 +02:00
Huang Xin 915f222e08 doc: add a troubleshooting section in README (#837) 2025-04-08 18:05:22 +08:00
Huang Xin 9446df1b9c feat: add an option to configure default CJK fonts in CJK environments, closes #780 (#836) 2025-04-08 11:27:59 +02:00
Huang Xin bfcf89b093 fix: toggle the menus on the whole screen when Click-To-Flip is disabled, closes #831 (#834) 2025-04-08 08:09:46 +02:00
Huang Xin b0cf087d78 fix: support opening content URIs by copying to cache when direct access fails, closes #829 (#833) 2025-04-08 07:45:33 +02:00
Huang Xin 5863586766 feat: vertical layout for highlighting tools, closes #787 (#830) 2025-04-07 17:24:14 +02:00
Huang Xin 99182a1f9e feat: add configurable timeout to stop TTS playback automatically, closes #747 (#826) 2025-04-07 12:40:14 +02:00
Huang Xin 2599f40dfb feat: add option to keep window on top, closes #820 (#825) 2025-04-07 08:23:46 +02:00
Huang Xin aa66ba54c5 fix: set proper default theme mode, closes #823 (#824) 2025-04-07 07:16:31 +02:00
Huang Xin 4f0ef01a17 fix: tts now works in background in iOS, closes #547 (#822)
To enable background playback in Android, go to Settings > Apps & Notifications > Readest > Battery > Battery Optimization, and disable battery optimization for Readest.
2025-04-06 18:42:58 +02:00
Huang Xin 267e1656db release: version 0.9.30 (#817) 2025-04-05 11:39:37 +02:00
Huang Xin dcecda2984 fix: cache NativeFile with LRU, closes #797 (#816) 2025-04-05 11:27:07 +02:00
Huang Xin ce88f0229a fix: rounded reader widget only when sidebar is invisible , closes #809 (#815) 2025-04-05 10:08:39 +02:00
Huang Xin 316c82ea52 fix: override link color only when overriding font, closes #812 (#814) 2025-04-05 09:34:29 +02:00
Huang Xin 25be60ce2a chore: bump tauri to 2.4.1 (#813) 2025-04-05 07:40:33 +02:00
Huang Xin 4703eec045 fix: set correct filename in openFile API, closes #803 (#810) 2025-04-05 12:41:26 +08:00
Huang Xin ab22a83332 fix: open default file chooser on Android, closes #798 and closes #799 (#807) 2025-04-04 05:01:12 +02:00
Huang Xin a3d6ebe44d feat: add fixed storage quota for self-hosted instance, closes #805 (#806) 2025-04-04 03:48:43 +02:00
Huang Xin f8804b5d3c fix: revert font family, size and color when overrideFont is set, closes #792 (#804) 2025-04-03 17:15:19 +02:00
Huang Xin ee3785ad51 fix: hack to decode incorrectly encoded url in href (#796) 2025-04-02 07:35:00 +02:00
758 changed files with 119093 additions and 17788 deletions
+33
View File
@@ -0,0 +1,33 @@
# Dependencies
node_modules
**/node_modules
# Rust build artifacts
target
**/target
# Git
.git
.gitignore
# Build outputs
dist
**/dist
.next
**/.next
out
**/out
# IDE
.idea
.vscode
*.swp
# OS files
.DS_Store
Thumbs.db
# Logs
*.log
npm-debug.log*
+15
View File
@@ -0,0 +1,15 @@
# These are supported funding model platforms
github: ['readest']
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+8 -4
View File
@@ -7,13 +7,17 @@ assignees: ''
---
**Does your feature request involve difficulty for you to complete a task? Please describe.**
A clear and concise description of what the problem is. Ex. I think it takes too many steps to [...]
> A clear and concise description of what the problem is. Ex. I think it takes too many steps to [...]
**Describe the solution you'd like**
A clear and concise description of what you'd like to happen.
> A clear and concise description of what you'd like to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
> A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any additional context or screenshots about the feature request here.
> Add any additional context or screenshots about the feature request here.
+10 -19
View File
@@ -11,22 +11,16 @@ assignees: ''
A clear and concise description of what the current behavior is.
Please also add **screenshots** of the existing application.
**Example:**
```
In DarkMode, when scrollbar are displayed (for example on Companies page, with enough companies in the list), we see a blank square in the bottom right corner
[screenshot]
```
> **Example:**
> In DarkMode, when scrollbar are displayed (for example on Companies page, with enough companies in the list), we see a blank square in the bottom right corner
> [screenshot]
## Expected behavior
A clear and concise description of what the expected behavior is.
**Example:**
```
The blank square should be transparent (invisible)
```
> **Example:**
> The blank square should be transparent (invisible)
## Technical inputs
@@ -34,11 +28,8 @@ Operating System:
Readest Version:
**Example:**
```
Operating System: macOS 14.3.1
Readest Version: 0.9.0
We are displaying custom scrollbars that disappear when the user is not scrolling. See ScrollWrapper.
Probably fixable with CSS
```
> **Example:**
> Operating System: Android 14 (WebView 135.0)
> Readest Version: 0.9.0
> We are displaying custom scrollbars that disappear when the user is not scrolling. See ScrollWrapper.
> Probably fixable with CSS
+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
+43 -9
View File
@@ -11,7 +11,7 @@ jobs:
env:
RUSTFLAGS: '-C target-cpu=skylake'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: 'true'
- name: Install minimal stable with clippy and rustfmt
@@ -19,6 +19,7 @@ jobs:
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Install system dependencies
run: |
sudo apt-get update
@@ -28,32 +29,65 @@ jobs:
run: cargo fmt --check
- name: Clippy Check
working-directory: apps/readest-app/src-tauri
run: cargo clippy -- -D warnings
run: cargo clippy -p Readest --no-deps -- -D warnings
build_web_app:
runs-on: ubuntu-latest
strategy:
matrix:
config:
- platform: 'web'
- platform: 'tauri'
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
- name: setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm
- name: cache Next.js build
uses: actions/cache@v5
with:
path: apps/readest-app/.next/cache
key: nextjs-${{ matrix.config.platform }}-${{ github.sha }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
nextjs-${{ matrix.config.platform }}-${{ github.sha }}-
nextjs-${{ matrix.config.platform }}-
- 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: run tests
working-directory: apps/readest-app
run: |
pnpm build-web
pnpm test -- --watch=false
- name: run lint
working-directory: apps/readest-app
run: |
pnpm lint
- name: build the web App
if: matrix.config.platform == 'web'
working-directory: apps/readest-app
run: |
pnpm build-web && pnpm check:all
- name: build the Tauri App
if: matrix.config.platform == 'tauri'
working-directory: apps/readest-app
run: |
pnpm build && pnpm check:all
+187 -47
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,6 +124,11 @@ 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
@@ -76,7 +138,7 @@ jobs:
release: windows
arch: x86_64
rust_target: x86_64-pc-windows-msvc
args: '--target x86_64-pc-windows-msvc'
args: '--target x86_64-pc-windows-msvc --bundles nsis'
- os: windows-latest
release: windows
arch: aarch64
@@ -86,25 +148,23 @@ 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
- name: setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
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'
@@ -115,13 +175,13 @@ jobs:
- 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
@@ -130,14 +190,25 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.config.os }}-cargo-${{ hashFiles('Cargo.lock') }}
key: ${{ matrix.config.os }}-${{ matrix.config.release }}-${{ matrix.config.arch }}-cargo
- name: install dependencies (ubuntu only)
if: contains(matrix.config.os, 'ubuntu') && matrix.config.release != 'android'
if: contains(matrix.config.os, 'ubuntu') && matrix.config.release != 'android' && matrix.config.arch != 'armhf'
run: |
sudo apt-get update
sudo apt-get install -y pkg-config libfontconfig-dev libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf xdg-utils
- name: install dependencies (ubuntu only - armhf specific)
if: contains(matrix.config.os, 'ubuntu') && matrix.config.arch == 'armhf'
run: |
sudo dpkg --add-architecture armhf
sudo apt-get update
sudo apt-get install -y pkg-config libfontconfig-dev:armhf libgtk-3-dev:armhf libwebkit2gtk-4.1-dev:armhf libappindicator3-dev:armhf librsvg2-dev:armhf gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
echo 'PKG_CONFIG_ALLOW_CROSS=1' >> $GITHUB_ENV
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
- name: create .env.local file for Next.js
run: |
echo "NEXT_PUBLIC_POSTHOG_KEY=${{ secrets.NEXT_PUBLIC_POSTHOG_KEY }}" >> .env.local
@@ -151,7 +222,9 @@ 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: |
cd apps/readest-app/
rm -rf src-tauri/gen/android
@@ -179,11 +252,47 @@ jobs:
gh release upload ${{ needs.get-release.outputs.release_tag }} $universial_apk --clobber
echo "Uploading $arm64_apk to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} $arm64_apk --clobber
echo "Uploading signatures to GitHub release"
pnpm tauri signer sign $universial_apk
pnpm tauri signer sign $arm64_apk
gh release upload ${{ needs.get-release.outputs.release_tag }} $universial_apk.sig --clobber
gh release upload ${{ needs.get-release.outputs.release_tag }} $arm64_apk.sig --clobber
- name: download and update latest.json for Android release
if: matrix.config.release == 'android'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd apps/readest-app/
curl -sL https://github.com/readest/readest/releases/latest/download/latest.json -o latest.json
version=${{ needs.get-release.outputs.release_version }}
universial_apk_url="https://github.com/readest/readest/releases/download/${{ needs.get-release.outputs.release_tag }}/Readest_${version}_universal.apk"
arm64_apk_url="https://github.com/readest/readest/releases/download/${{ needs.get-release.outputs.release_tag }}/Readest_${version}_arm64.apk"
universial_sig=$(cat Readest_${version}_universal.apk.sig)
arm64_sig=$(cat Readest_${version}_arm64.apk.sig)
jq --arg url "$universial_apk_url" \
--arg sig "$universial_sig" \
'.platforms["android-universal"] = {signature: $sig, url: $url}' latest.json > tmp.$$.json && mv tmp.$$.json latest.json
jq --arg url "$arm64_apk_url" \
--arg sig "$arm64_sig" \
'.platforms["android-arm64"] = {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
- 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 }}
@@ -199,12 +308,29 @@ jobs:
releaseBody: ${{ needs.get-release.outputs.release_note }}
args: ${{ matrix.config.args || '' }}
- name: upload portable binaries (Windows only)
- name: upload release notes to GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Uploading release notes to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} apps/readest-app/release-notes.json --clobber
- 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 }}
@@ -227,35 +353,49 @@ 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, build-tauri]
uses: ./.github/workflows/upload-to-r2.yml
with:
tag: ${{ needs.get-release.outputs.release_tag }}
secrets: inherit
+18
View File
@@ -0,0 +1,18 @@
name: Retry workflow
on:
workflow_dispatch:
inputs:
run_id:
required: true
jobs:
rerun:
runs-on: ubuntu-latest
steps:
- name: rerun ${{ inputs.run_id }}
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
gh run watch ${{ inputs.run_id }} > /dev/null 2>&1
gh run rerun ${{ inputs.run_id }} --failed
+77
View File
@@ -0,0 +1,77 @@
name: Upload Release Assets to R2
on:
workflow_call:
inputs:
tag:
required: true
type: string
workflow_dispatch:
inputs:
tag:
description: 'Release tag name (e.g., v1.2.3)'
required: true
type: string
jobs:
upload-to-r2:
runs-on: ubuntu-latest
timeout-minutes: 3
strategy:
fail-fast: false
env:
RELEASE_R2_BUCKET: readest-releases
RELEASE_R2_ACCOUNT_ID: ${{ secrets.RELEASE_R2_ACCOUNT_ID }}
RELEASE_R2_ACCESS_KEY_ID: ${{ secrets.RELEASE_R2_ACCESS_KEY_ID }}
RELEASE_R2_SECRET_ACCESS_KEY: ${{ secrets.RELEASE_R2_SECRET_ACCESS_KEY }}
steps:
- name: Download release assets
run: |
gh release download "${{ inputs.tag }}" --repo readest/readest --dir ./release-assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install rclone
run: curl https://rclone.org/install.sh | sudo bash
- name: Configure rclone
run: |
mkdir -p ~/.config/rclone
cat > ~/.config/rclone/rclone.conf <<EOF
[r2]
type = s3
provider = Cloudflare
access_key_id = $RELEASE_R2_ACCESS_KEY_ID
secret_access_key = $RELEASE_R2_SECRET_ACCESS_KEY
endpoint = https://${RELEASE_R2_ACCOUNT_ID}.r2.cloudflarestorage.com
EOF
- name: Modify latest.json download URLs
run: |
GITHUB_BASE_URL="https://github.com/readest/readest/releases/download"
READEST_BASE_URL="https://download.readest.com/releases"
sed -i "s#${GITHUB_BASE_URL}#${READEST_BASE_URL}#g" ./release-assets/latest.json
- name: Upload to R2
run: |
mkdir releases
mv ./release-assets/latest.json releases
mv ./release-assets/release-notes.json releases
rclone copy ./release-assets r2:${RELEASE_R2_BUCKET}/releases/${{ inputs.tag }}/
rclone copy ./releases r2:${RELEASE_R2_BUCKET}/releases/
- name: Upload successful
if: success()
run: echo "Upload completed successfully"
retry-on-failure:
if: failure() && fromJSON(github.run_attempt) < 3
needs: [upload-to-r2]
runs-on: ubuntu-latest
steps:
- env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: gh workflow run retry-workflow.yml -F run_id=${{ github.run_id }}
+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
+8
View File
@@ -38,3 +38,11 @@ next-env.d.ts
# Rust build
target
fastlane/report.xml
*.koplugin.zip
# nix
result*
.playwright-mcp/
+7 -1
View File
@@ -3,4 +3,10 @@
url = https://github.com/readest/foliate-js.git
[submodule "packages/tauri"]
path = packages/tauri
url = https://github.com/tauri-apps/tauri.git
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
+34 -1
View File
@@ -1 +1,34 @@
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
# Vendored Assets (Generated/External Code)
apps/readest-app/public/*.js
apps/readest-app/public/vendor
# 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"
]
}
+25 -1
View File
@@ -4,4 +4,28 @@
"packages/tauri/Cargo.toml",
"apps/readest-app/src-tauri/Cargo.toml"
],
}
// "editor.formatOnSave": true, // uncomment to add format on save
"typescript.inlayHints.parameterNames.enabled": "all",
"typescript.inlayHints.variableTypes.enabled": true,
"typescript.inlayHints.propertyDeclarationTypes.enabled": true,
"typescript.inlayHints.functionLikeReturnTypes.enabled": true,
"typescript.inlayHints.enumMemberValues.enabled": true,
"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
+1780 -1473
View File
File diff suppressed because it is too large Load Diff
+25 -1
View File
@@ -2,9 +2,29 @@
members = [
"apps/readest-app/src-tauri",
"packages/tauri/crates/tauri",
"packages/tauri/crates/tauri-utils",
"packages/tauri/crates/tauri-build",
"packages/tauri-plugins/plugins/deep-link",
"packages/tauri-plugins/plugins/single-instance"
]
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"
[workspace.package]
authors = ["Bilingify LLC"]
homepage = "https://readest.com"
@@ -15,4 +35,8 @@ edition = "2021"
rust-version = "1.77.2"
[patch.crates-io]
tauri = { path = "packages/tauri/crates/tauri" }
tauri = { path = "packages/tauri/crates/tauri" }
tauri-utils = { path = "packages/tauri/crates/tauri-utils" }
tauri-build = { path = "packages/tauri/crates/tauri-build" }
tauri-plugin-deep-link = { path = "packages/tauri-plugins/plugins/deep-link" }
tauri-plugin-single-instance = { path = "packages/tauri-plugins/plugins/single-instance" }
+1 -19
View File
@@ -5,31 +5,13 @@ 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
WORKDIR /app
RUN pnpm install
RUN pnpm --filter @readest/readest-app setup-pdfjs
RUN pnpm --filter @readest/readest-app setup-vendors
WORKDIR /app/apps/readest-app
+117 -42
View File
@@ -5,18 +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)
[![Language Coverage][badge-language-coverage]][link-locales]
[![Donate][badge-donate]][link-donate]
[![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>
@@ -26,7 +30,8 @@
<a href="#screenshots">Screenshots</a> •
<a href="#downloads">Downloads</a> •
<a href="#getting-started">Getting Started</a> •
<a href="#contributors">Contributors</a> •
<a href="#troubleshooting">Troubleshooting</a> •
<a href="#support">Support</a> •
<a href="#license">License</a>
</p>
@@ -40,37 +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. | ✅ |
| **Translate with DeepL** | Translate selected text instantly using DeepL for accurate translations. | ✅ |
| **[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. | ✅ |
| **Text-to-Speech (TTS) Support** | Enable text-to-speech functionality for a more accessible reading experience. | ✅ |
| **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. | ✅ |
| **Accessibility** | Provides full keyboard navigation and supports for screen readers such as VoiceOver, TalkBack, NVDA, and Orca. | ✅ |
| **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. | ✅ |
| **Library Management** | Organize, sort, and manage your entire ebook library. | ✅ |
| **OPDS/Calibre Integration** | Integrate OPDS/Calibre to access online libraries and catalogs. | ✅ |
| **Code Syntax Highlighting** | Read software manuals with rich coloring of code examples. | ✅ |
## Planned Features
<div align="left">🛠 Building</div>
<div align="left">🔄 Planned</div>
| **Feature** | **Description** | **Priority** |
| ------------------------------- | ------------------------------------------------------------------------------------------ | ------------ |
| **Library Management** | Organize, sort, and manage your entire ebook library. | 🛠 |
| **AI-Powered Summarization** | Generate summaries of books or chapters using AI for quick insights. | 🛠 |
| **Sync with Koreader** | Synchronize reading progress, notes, and bookmarks with [Koreader][link-koreader] devices. | 🔄 |
| **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** |
| ------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------ |
| [**Sync with Koreader**][link-kosync-wiki] | 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. | 🛠 |
| **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. | 🔄 |
Stay tuned for continuous improvements and updates! Contributions and suggestions are always welcome—let's build the ultimate reading experience together. 😊
@@ -78,25 +84,35 @@ Stay tuned for continuous improvements and updates! Contributions and suggestion
![Annotations](./data/screenshots/annotations.png)
![DeepL](./data/screenshots/deepl.png)
![TTS](./data/screenshots/tts_speak_aloud.png)
![DeepL](./data/screenshots/deepl.png)
![Footnote](./data/screenshots/footnote_popover.png)
![Wikipedia](./data/screenshots/wikipedia_vertical.png)
![Themeing Dark Mode](./data/screenshots/theming_dark_mode.png)
![Theming Dark Mode](./data/screenshots/theming_dark_mode.png)
---
## Downloads
The Readest app is available for download! 🥳 🚀
### Mobile Apps
- 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].
<div align="center">
<a href="https://apps.apple.com/app/id6738622779">
<img alt="Download on the App Store" src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg" style="height: 50px;" /></a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://play.google.com/store/apps/details?id=com.bilingify.readest">
<img alt="Get it on Google Play" src="https://upload.wikimedia.org/wikipedia/commons/7/78/Google_Play_Store_badge_EN.svg" style="height: 50px;" /></a>
</div>
### Platform-Specific Downloads
- 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
@@ -121,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
@@ -152,6 +168,8 @@ 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:
@@ -199,6 +217,39 @@ nix develop ./ops#android # enter a dev shell for the android app
Please check the [wiki][link-gh-wiki] of this project for more information on development.
## Troubleshooting
### 1. Readest Wont Launch on Windows (Missing Edge WebView2 Runtime)
**Symptom**
- When you double-click readest.exe, nothing happens. No window appears, and Task Manager does not show the process.
- This can affect both the standard installer and the portable version.
**Cause**
- Microsoft Edge WebView2 Runtime is either missing, outdated, or improperly installed on your system. Readest depends on WebView2 to render the interface on Windows.
**How to Fix**
1. Check if WebView2 is installed
- Open “Add or Remove Programs” (a.k.a. Apps & features) on Windows. Look for “Microsoft Edge WebView2 Runtime.”
2. Install or Update WebView2
- Download the WebView2 Runtime directly from Microsoft: [link](https://developer.microsoft.com/en-us/microsoft-edge/webview2?form=MA13LH).
- If you prefer an offline installer, download the offline package and run it as an Administrator.
3. Re-run Readest
- After installing/updating WebView2, launch readest.exe again.
- If you still encounter problems, reboot your PC and try again.
**Additional Tips**
- If reinstalling once doesnt work, uninstall Edge WebView2 completely, then reinstall it with Administrator privileges.
- Verify your Windows installation has the latest updates from Microsoft.
**Still Stuck?**
- 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.
## 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.
@@ -209,6 +260,18 @@ Readest is open-source, and contributions are welcome! Feel free to open issues,
</p>
</a>
## Support
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 [contribute with crypto](https://donate.readest.com). Your contribution helps us squash bugs faster, improve performance, and keep building great features.
### Sponsors
<p align="center">
<a title="Browser testing via TestMu AI" href="https://www.testmu.ai?utm_source=readest&utm_medium=sponsor" 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
Readest is free software: you can redistribute it and/or modify it under the terms of the [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See the [LICENSE](LICENSE) file for details.
@@ -219,9 +282,11 @@ The following libraries and frameworks are used in this software:
- [zip.js](https://github.com/gildas-lormeau/zip.js), which is licensed under the BSD-3-Clause license.
- [fflate](https://github.com/101arrowz/fflate), which is MIT licensed.
- [PDF.js](https://github.com/mozilla/pdf.js), which is licensed under Apache License 2.0.
- [daisyUI](https://github.com/saadeghi/daisyui), which is MIT licensed.
- [marked](https://github.com/markedjs/marked), which is MIT licensed.
- [next.js](https://github.com/vercel/next.js), which is MIT licensed.
- [react](https://github.com/facebook/react), which is MIT licensed.
- [react-icons](https://github.com/react-icons/react-icons), which has various open-source licenses.
- [react](https://github.com/facebook/react), which is MIT licensed.
- [tauri](https://github.com/tauri-apps/tauri), which is MIT licensed.
The following fonts are utilized in this software, either bundled within the application or provided through web fonts:
@@ -237,12 +302,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
@@ -252,3 +323,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/
+8 -2
View File
@@ -2,5 +2,11 @@ PDFJS_BUILD_PATH=../../packages/foliate-js/node_modules/pdfjs-dist/legacy/build
PDFJS_FONTS_PATH=../../packages/foliate-js/node_modules/pdfjs-dist
PDFJS_STYLE_PATH=../../packages/foliate-js/vendor/pdfjs
NEXT_PUBLIC_DEV_SUPABASE_URL=https://gxkhxxxeapexynpouyjz.supabase.co
NEXT_PUBLIC_DEV_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imd4a2h4eHhlYXBleHlucG91eWp6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzQ0MzAwNTksImV4cCI6MjA1MDAwNjA1OX0.jhinkQsimQoidsg_U59YD5ROw4PmMJQNKuyXbr4TiQA
NEXT_PUBLIC_DEFAULT_POSTHOG_URL_BASE64="aHR0cHM6Ly91cy5pLnBvc3Rob2cuY29t"
NEXT_PUBLIC_DEFAULT_POSTHOG_KEY_BASE64="cGhjX2ViNXowbVRxWm8yZm5YYnZGNmE3bFh5TThpTmRSNTNsR1A3VFM3VGh4S08="
NEXT_PUBLIC_DEFAULT_SUPABASE_URL_BASE64="aHR0cHM6Ly9yZWFkZXN0LnN1cGFiYXNlLmNv"
NEXT_PUBLIC_DEFAULT_SUPABASE_KEY_BASE64="ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKemRYQmhZbUZ6WlNJc0luSmxaaUk2SW5aaWMzbDRablZ6YW1weFpIaHJhbkZzZVhOaklpd2ljbTlzWlNJNkltRnViMjRpTENKcFlYUWlPakUzTXpReE1qTTJOekVzSW1WNGNDSTZNakEwT1RZNU9UWTNNWDAuM1U1VXFhb3VfMVNnclZlMWVvOXJBcGMwdUtqcWhwUWRVWGh2d1VIbVVmZw=="
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_DEV_BASE64="cGtfdGVzdF81MVJmQmdLRTdSWW5pTWsxc0tDV2RUd2hMZzcySzk4eDRWcjlIdDdsRFBONngzcnpZYmhydGtNQnpDdzZKbHFaRVVITVp5eVNjVXhCZXVkcGppWTk0WXNHcDAweFlRRnRRaUU="
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_BASE64="cGtfbGl2ZV81MVFYN3dRRU5ndjJFOUxQRHpZUlE5TlJJeTNjd09EZ1AzSkNFRHRPWlFtdFJWc3Brd053ZE1NNUpIVnVPTmJWcjZ3VGFCMUNZR1pJMmRPVWppTkY0bHJvVjAwalE4TkpkdWk="
+6
View File
@@ -4,6 +4,10 @@ NEXT_PUBLIC_POSTHOG_HOST=YOUR_POSTHOG_HOST
NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
NEXT_PUBLIC_STORAGE_FIXED_QUOTA=1073741824
NEXT_PUBLIC_API_BASE_URL=https://your-api-base-url.com
SUPABASE_ADMIN_KEY=YOUR_SUPABASE_ADMIN_KEY
DEEPL_PRO_API_KEYS=YOUR_DEEPL_PRO_API_KEYS
@@ -24,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
+1 -1
View File
@@ -32,7 +32,7 @@ yarn-error.log*
/private_keys
# plists
*.plist
Entitlements*.plist
# local confs
tauri.*.conf.json
+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": {}
}
+34 -12
View File
@@ -1,13 +1,35 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
import { defineConfig, globalIgnores } from 'eslint/config';
import next from 'eslint-config-next';
import nextVitals from 'eslint-config-next/core-web-vitals';
import tseslint from 'eslint-config-next/typescript';
import jsxA11y from 'eslint-plugin-jsx-a11y';
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")];
const eslintConfig = defineConfig([
...tseslint,
...next,
...nextVitals,
{
rules: {
...jsxA11y.configs.recommended.rules,
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
globalIgnores([
'node_modules/**',
'.next/**',
'.open-next/**',
'out/**',
'build/**',
'public/**',
'next-env.d.ts',
]),
]);
export default eslintConfig;
+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::*;
@@ -12,11 +12,14 @@ module.exports = {
'de',
'ja',
'es',
'fa',
'fr',
'it',
'el',
'ko',
'uk',
'nl',
'sv',
'pl',
'pt',
'ru',
@@ -24,7 +27,13 @@ module.exports = {
'hi',
'id',
'vi',
'ms',
'ar',
'th',
'bo',
'bn',
'ta',
'si',
'zh-CN',
'zh-TW',
],
+72 -16
View File
@@ -1,13 +1,22 @@
import withPWAInit from '@ducanh2912/next-pwa';
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();
}
const exportOutput = appPlatform !== 'web' && !isDev;
/** @type {import('next').NextConfig} */
const nextConfig = {
// Ensure Next.js uses SSG instead of SSR
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
output: appPlatform === 'web' || isDev ? undefined : 'export',
output: exportOutput ? 'export' : undefined,
pageExtensions: exportOutput ? ['jsx', 'tsx'] : ['js', 'jsx', 'ts', 'tsx'],
// Note: This feature is required to use the Next.js Image component in SSG mode.
// See https://nextjs.org/docs/messages/export-image-api for different workarounds.
images: {
@@ -17,6 +26,39 @@ 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',
};
return config;
},
turbopack: {
resolveAlias: {
nunjucks: 'nunjucks/browser/nunjucks.js',
},
},
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 headers() {
return [
{
@@ -28,23 +70,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));
+5 -28
View File
@@ -1,29 +1,6 @@
// @ts-nocheck
// default open-next.config.ts file created by @opennextjs/cloudflare
import { defineCloudflareConfig } from '@opennextjs/cloudflare';
import r2IncrementalCache from '@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache';
import type { OpenNextConfig } from '@opennextjs/aws/types/open-next.js';
import cache from '@opennextjs/cloudflare/kv-cache';
const config: OpenNextConfig = {
default: {
override: {
wrapper: 'cloudflare-node',
converter: 'edge',
// set `incrementalCache` to "dummy" to disable KV cache
incrementalCache: async () => cache,
tagCache: 'dummy',
queue: 'dummy',
},
},
middleware: {
external: true,
override: {
wrapper: 'cloudflare-edge',
converter: 'edge',
proxyExternalRequest: 'fetch',
},
},
};
export default config;
export default defineCloudflareConfig({
incrementalCache: r2IncrementalCache,
});
+129 -38
View File
@@ -1,6 +1,6 @@
{
"name": "@readest/readest-app",
"version": "0.9.29",
"version": "0.9.99",
"private": true,
"scripts": {
"dev": "dotenv -e .env.tauri -- next dev",
@@ -9,17 +9,26 @@
"dev-web": "dotenv -e .env.web -- next dev",
"build-web": "dotenv -e .env.web -- next build",
"start-web": "dotenv -e .env.web -- next start",
"build-tauri": "dotenv -e .env.tauri -- next build",
"i18n:extract": "i18next-scanner",
"lint": "next lint",
"lint": "eslint .",
"test": "dotenv -e .env -e .env.test.local vitest",
"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",
"clippy": "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",
@@ -30,78 +39,160 @@
"build-ios-appstore": "dotenv -e .env.ios-appstore.local -- tauri ios build --export-method app-store-connect",
"release-macos-universial-appstore": "dotenv -e .env.tauri.local -e .env.apple-appstore.local -- bash scripts/release-mac-appstore.sh",
"release-ios-appstore": "dotenv -e .env.ios-appstore.local -- bash scripts/release-ios-appstore.sh",
"preview": "NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare && wrangler dev",
"deploy": "NEXT_PUBLIC_APP_PLATFORM=web opennextjs-cloudflare && wrangler deploy",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
"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": "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": {
"@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.735.0",
"@aws-sdk/s3-request-presigner": "^3.735.0",
"@ducanh2912/next-pwa": "^10.2.9",
"@choochmeque/tauri-plugin-sharekit-api": "^0.3.0",
"@fabianlars/tauri-plugin-oauth": "2",
"@opennextjs/cloudflare": "^1.15.1",
"@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.4.2",
"@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.47.7",
"@tauri-apps/api": "2.3.0",
"@tauri-apps/plugin-cli": "^2.2.0",
"@tauri-apps/plugin-deep-link": "^2.2.0",
"@tauri-apps/plugin-dialog": "^2.2.0",
"@tauri-apps/plugin-fs": "^2.2.0",
"@tauri-apps/plugin-haptics": "^2.2.3",
"@tauri-apps/plugin-http": "^2.3.0",
"@tauri-apps/plugin-log": "^2.2.3",
"@tauri-apps/plugin-opener": "^2.2.6",
"@tauri-apps/plugin-os": "^2.2.0",
"@tauri-apps/plugin-process": "^2.2.0",
"@tauri-apps/plugin-shell": "~2.2.0",
"@tauri-apps/plugin-updater": "^2.5.1",
"@zip.js/zip.js": "^2.7.53",
"@supabase/supabase-js": "^2.76.1",
"@tauri-apps/api": "2.9.1",
"@tauri-apps/plugin-cli": "^2.4.1",
"@tauri-apps/plugin-deep-link": "^2.4.6",
"@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.6",
"@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.4",
"@tauri-apps/plugin-updater": "^2.9.0",
"@tauri-apps/plugin-websocket": "~2.4.2",
"@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",
"next": "15.2.4",
"posthog-js": "^1.205.0",
"react": "19.0.0",
"lucide-react": "^0.562.0",
"lunr": "^2.3.9",
"marked": "^15.0.12",
"nanoid": "^5.1.6",
"next": "16.1.6",
"nunjucks": "^3.2.4",
"overlayscrollbars": "^2.11.4",
"overlayscrollbars-react": "^0.5.6",
"posthog-js": "^1.246.0",
"react": "19.2.0",
"react-color": "^2.19.3",
"react-dom": "19.0.0",
"react-dom": "19.2.0",
"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",
"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": {
"@opennextjs/cloudflare": "^0.5.12",
"@tauri-apps/cli": "2.3.1",
"@next/bundle-analyzer": "^15.4.2",
"@tailwindcss/typography": "^0.5.16",
"@tauri-apps/cli": "2.9.6",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.3.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/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-eslint/eslint-plugin": "^8.48.0",
"@typescript-eslint/parser": "^8.48.0",
"@vitejs/plugin-react": "^5.1.1",
"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",
"eslint-config-next": "16.0.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"i18next-scanner": "^4.6.0",
"jsdom": "^26.1.0",
"mkdirp": "^3.0.1",
"node-env-run": "^4.0.2",
"postcss": "^8.4.49",
"postcss-cli": "^11.0.0",
"postcss-nested": "^7.0.2",
"raw-loader": "^4.0.2",
"tailwindcss": "^3.4.17",
"serwist": "^9.3.0",
"tailwindcss": "^3.4.18",
"typescript": "^5.7.2",
"wrangler": "^4.4.0"
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.15",
"wrangler": "^4.60.0"
}
}
@@ -1,11 +1,15 @@
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "com.bilingify.readest",
"sha256_cert_fingerprints": [
"65:2D:11:67:76:12:29:14:18:42:CB:3D:18:50:B6:E4:7E:46:E1:2F:4B:E4:7F:5A:6C:14:B6:D7:12:74:1E:82"
"65:2D:11:67:76:12:29:14:18:42:CB:3D:18:50:B6:E4:7E:46:E1:2F:4B:E4:7F:5A:6C:14:B6:D7:12:74:1E:82",
"E0:E7:60:55:80:8D:3A:DE:A0:D1:CF:7C:20:85:40:A3:DD:4B:E6:4D:17:5C:0F:DE:26:57:7D:9C:5B:29:5F:51"
]
}
}
@@ -0,0 +1 @@
ed533042-5626-4704-b5f2-fa3bbd1136ed
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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,3 +1,27 @@
{
"LXGW WenKai GB Screen": "LXGW WenKai"
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"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",
"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
@@ -5,11 +5,9 @@
"Animation": "एनीमेशन",
"Annotate": "टिप्पणी",
"Apply": "लागू करें",
"Are you sure to delete the selected books?": "क्या आप चयनित पुस्तकों को हटाना चाहते हैं?",
"Auto Mode": "स्वचालित मोड",
"Behavior": "व्यवहार",
"Book": "पुस्तक",
"Book Cover": "पुस्तक का कवर",
"Bookmark": "बुकमार्क",
"Cancel": "रद्द करें",
"Chapter": "अध्याय",
@@ -19,7 +17,6 @@
"Confirm Deletion": "हटाने की पुष्टि करें",
"Copied to notebook": "नोटबुक में कॉपी किया गया",
"Copy": "कॉपी",
"Custom CSS": "कस्टम CSS",
"Dark Mode": "डार्क मोड",
"Default": "डिफ़ॉल्ट",
"Default Font": "डिफ़ॉल्ट फ़ॉन्ट",
@@ -27,10 +24,8 @@
"Delete": "हटाएं",
"Delete Highlight": "हाइलाइट हटाएं",
"Dictionary": "शब्दकोश",
"Disable Click-to-Flip": "क्लिक-टू-फ्लिप अक्षम करें",
"Download Readest": "Readest डाउनलोड करें",
"Edit": "संपादित करें",
"Enter your custom CSS here...": "अपना कस्टम CSS यहां दर्ज करें...",
"Excerpts": "अंश",
"Failed to import book(s): {{filenames}}": "पुस्तक(ें) आयात करने में विफल: {{filenames}}",
"Fast": "तेज़",
@@ -43,17 +38,13 @@
"Global Settings": "वैश्विक सेटिंग्स",
"Go Back": "वापस जाएं",
"Go Forward": "आगे जाएं",
"Go Left": "बाएं जाएं",
"Go Right": "दाएं जाएं",
"Grass": "घास",
"Gray": "ग्रे",
"Gruvbox": "ग्रूवबॉक्स",
"Highlight": "हाइलाइट",
"Horizontal Direction": "क्षैतिज दिशा",
"Hyphenation": "हाइफ़नेशन",
"Identifier:": "पहचानकर्ता:",
"Import Books": "पुस्तकें आयात करें",
"Language:": "भाषा:",
"Layout": "लेआउट",
"Light Mode": "लाइट मोड",
"Loading...": "लोड हो रहा है...",
@@ -64,7 +55,6 @@
"Match Whole Words": "पूरे शब्द मैच करें",
"Maximum Number of Columns": "कॉलम की अधिकतम संख्या",
"Minimum Font Size": "न्यूनतम फ़ॉन्ट साइज़",
"Misc": "विविध",
"Monospace Font": "मोनोस्पेस फ़ॉन्ट",
"More Info": "अधिक जानकारी",
"Nord": "नॉर्ड",
@@ -76,8 +66,8 @@
"Paging Animation": "पेजिंग एनीमेशन",
"Paragraph": "पैराग्राफ",
"Parallel Read": "समानांतर पढ़ें",
"Published:": "प्रकाशित:",
"Publisher:": "प्रकाशक:",
"Published": "प्रकाशित",
"Publisher": "प्रकाशक",
"Reading Progress Synced": "पढ़ने की प्रगति सिंक की गई",
"Reload Page": "पृष्ठ रीलोड करें",
"Reveal in File Explorer": "फ़ाइल एक्सप्लोरर में दिखाएं",
@@ -91,7 +81,6 @@
"Search...": "खोजें...",
"Select Book": "पुस्तक चुनें",
"Select Books": "पुस्तकें चुनें",
"Select Multiple Books": "कई पुस्तकें चुनें",
"Sepia": "सेपिया",
"Serif Font": "सेरिफ फ़ॉन्ट",
"Show Book Details": "पुस्तक विवरण दिखाएं",
@@ -102,17 +91,15 @@
"Slow": "धीमा",
"Solarized": "सोलराइज्ड",
"Speak": "बोलें",
"Subjects:": "विषय:",
"Subjects": "विषय",
"System Fonts": "सिस्टम फ़ॉन्ट्स",
"TTS not supported in this device": "यह डिवाइस TTS का समर्थन नहीं करता",
"Theme Color": "थीम रंग",
"Theme Mode": "थीम मोड",
"Translate": "अनुवाद करें",
"Translated Text": "अनुवादित पाठ",
"Unknown": "अज्ञात",
"Untitled": "शीर्षकहीन",
"Updated:": "अपडेट किया गया:",
"User avatar": "उपयोगकर्ता अवतार",
"Updated": "अपडेट किया गया",
"Version {{version}}": "संस्करण {{version}}",
"Vertical Direction": "ऊर्ध्वाधर दिशा",
"Welcome to your library. You can import your books here and read them anytime.": "आपकी लाइब्रेरी में आपका स्वागत है। आप यहां अपनी पुस्तकें आयात कर सकते हैं और कभी भी पढ़ सकते हैं।",
@@ -121,26 +108,21 @@
"Your Library": "आपकी लाइब्रेरी",
"TTS not supported for PDF": "PDF के लिए TTS समर्थित नहीं है",
"Override Book Font": "पुस्तक फ़ॉन्ट ओवरराइड करें",
"Vertical Margins (px)": "ऊर्ध्वाधर मार्जिन (px)",
"Horizontal Margins (%)": "क्षैतिज मार्जिन (%)",
"Apply to All Books": "सभी पुस्तकों पर लागू करें",
"Apply to This Book": "इस पुस्तक पर लागू करें",
"Unable to fetch the translation. Try again later.": "अनुवाद प्राप्त करने में असमर्थ। बाद में पुनः प्रयास करें।",
"Update Now!": "अभी अपडेट करें!",
"Update": "अपडेट करें",
"Check Update": "अपडेट जांचें",
"Already the latest version": "पहले से ही नवीनतम संस्करण",
"Book Details": "पुस्तक विवरण",
"From Local File": "स्थानीय फ़ाइल से",
"TOC": "सामग्री",
"Table of Contents": "सामग्री",
"Book uploaded: {{title}}": "पुस्तक अपलोड की गई: {{title}}",
"Failed to upload book: {{title}}": "पुस्तक अपलोड करने में विफल: {{title}}",
"Book downloaded: {{title}}": "पुस्तक डाउनलोड की गई: {{title}}",
"Failed to download book: {{title}}": "पुस्तक डाउनलोड करने में विफल: {{title}}",
"Upload Book": "पुस्तक अपलोड करें",
"Auto Upload Books to Cloud": "पुस्तकें बादल में स्वचालित रूप से अपलोड करें",
"{{percentage}}% of Cloud Storage Used.": "{{percentage}}% क्लाउड स्टोरेज का उपयोग किया गया है।",
"Storage": "स्टोरेज",
"Book deleted: {{title}}": "पुस्तक हटाई गई: {{title}}",
"Failed to delete book: {{title}}": "पुस्तक हटाने में विफल: {{title}}",
"Check Updates on Start": "शुरू में अपडेट जांचें",
@@ -172,7 +154,7 @@
"Create a Password": "पासवर्ड बनाएं",
"Sign up": "साइन अप करें",
"Signing up...": "साइन अप हो रहा है...",
"Dont have an account? Sign up": "कोई खाता नहीं है? साइन अप करें",
"Don't have an account? Sign up": "कोई खाता नहीं है? साइन अप करें",
"Check your email for the confirmation link": "पुष्टि लिंक के लिए अपना ईमेल जांचें",
"Signing in ...": "साइन इन हो रहा है ...",
"Send a magic link email": "जादू लिंक ईमेल भेजें",
@@ -191,41 +173,15 @@
"Token": "टोकन",
"Your OTP token": "आपका ओटीपी टोकन",
"Verify token": "टोकन सत्यापित करें",
"Sign in with Google": "Google के साथ साइन इन करें",
"Sign in with Apple": "Apple के साथ साइन इन करें",
"Sign in with GitHub": "GitHub के साथ साइन इन करें",
"Account": "खाता",
"Cloud Storage": "क्लाउड स्टोरेज",
"Failed to delete user. Please try again later.": "उपयोगकर्ता को हटाने में विफल। कृपया बाद में पुनः प्रयास करें।",
"Unlimited Offline/Online Reading": "असीमित ऑफलाइन/ऑनलाइन पढ़ना",
"Unlimited Cloud Sync Devices": "असीमित क्लाउड सिंक उपकरण",
"Essential Text-to-Speech Voices": "आवश्यक टेक्स्ट-टू-स्पीच आवाज़ें",
"DeepL Free Access": "DeepL मुफ्त पहुंच",
"Community Support": "सामुदायिक सहायता",
"500 MB Cloud Sync Space": "500 MB क्लाउड सिंक स्पेस",
"Includes All Free Tier Benefits": "सभी फ्री टियर लाभ शामिल हैं",
"AI Summaries": "AI सारांश",
"AI Translations": "AI अनुवाद",
"Priority Support": "प्राथमिकता सहायता",
"DeepL Pro Access": "DeepL प्रो पहुंच",
"Expanded Text-to-Speech Voices": "विस्तारित टेक्स्ट-टू-स्पीच आवाज़ें",
"2000 MB Cloud Sync Space": "2000 MB क्लाउड सिंक स्पेस",
"Includes All Plus Tier Benefits": "सभी प्लस टियर लाभ शामिल हैं",
"Unlimited AI Summaries": "असीमित AI सारांश",
"Unlimited AI Translations": "असीमित AI अनुवाद",
"Unlimited DeepL Pro Access": "असीमित DeepL प्रो पहुंच",
"Advanced AI Tools": "उन्नत AI टूल्स",
"Early Feature Access": "प्रारंभिक फीचर पहुंच",
"10 GB Cloud Sync Space": "10 GB क्लाउड सिंक स्पेस",
"Loading profile...": "प्रोफ़ाइल लोड हो रहा है...",
"Features": "विशेषताएं",
"Delete Account": "खाता हटाएं",
"Delete Your Account?": "अपना खाता हटाएं?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "यह क्रिया पूर्ववत नहीं की जा सकती। क्लाउड में आपका सभी डेटा स्थायी रूप से हटा दिया जाएगा।",
"Delete Permanently": "स्थायी रूप से हटाएं",
"Free Tier": "फ्री टियर",
"Plus Tier": "प्लस टियर",
"Pro Tier": "प्रो टियर",
"RTL Direction": "RTL दिशा",
"Maximum Column Height": "कॉलम की अधिकतम ऊँचाई",
"Maximum Column Width": "कॉलम की अधिकतम चौड़ाई",
@@ -234,7 +190,7 @@
"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": "टेक्स्ट रंग",
@@ -259,11 +215,821 @@
"Copied to clipboard": "क्लिपबोर्ड पर कॉपी किया गया",
"Export Annotations": "टिप्पणियाँ निर्यात करें",
"Auto Import on File Open": "फ़ाइल खोलने पर स्वचालित आयात",
"LXGW WenKai GB Screen": "LXGW WenKai",
"Swap Click-to-Flip Area": "क्लिक-टू-फ्लिप क्षेत्र स्वैप करें",
"No chapters detected.": "कोई अध्याय नहीं मिला।",
"Failed to parse the EPUB file.": "EPUB फ़ाइल को पार्स करने में विफल।",
"This book format is not supported.": "यह पुस्तक प्रारूप समर्थित नहीं है।",
"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": "यह पुस्तक प्रारूप समर्थित नहीं है।",
"Unable to fetch the translation. Please log in first and try again.": "अनुवाद प्राप्त करने में असमर्थ। कृपया पहले लॉग इन करें और पुनः प्रयास करें।",
"Group": "समूह"
"Group": "समूह",
"Always on Top": "सर्वोच्च पर हमेशा",
"No Timeout": "कोई समय समाप्त नहीं",
"{{value}} minute": "{{value}} मिनट",
"{{value}} minutes": "{{value}} मिनट",
"{{value}} hour": "{{value}} घंटा",
"{{value}} hours": "{{value}} घंटे",
"CJK Font": "CJK फ़ॉन्ट",
"Clear Search": "खोज साफ करें",
"Header & Footer": "हेडर और फ़ुटर",
"Apply also in Scrolled Mode": "स्क्रॉल मोड में भी लागू करें",
"A new version of Readest is available!": "Readest का एक नया संस्करण उपलब्ध है!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} उपलब्ध है (स्थापित संस्करण {{currentVersion}})।",
"Download and install now?": "अब डाउनलोड और इंस्टॉल करें?",
"Downloading {{downloaded}} of {{contentLength}}": "डाउनलोड कर रहा है {{downloaded}} का {{contentLength}}",
"Download finished": "डाउनलोड पूरा हुआ",
"DOWNLOAD & INSTALL": "डाउनलोड और इंस्टॉल करें",
"Changelog": "चेंजलॉग",
"Software Update": "सॉफ़्टवेयर अपडेट",
"Title": "शीर्षक",
"Date Read": "पढ़ने की तारीख",
"Date Added": "जोड़ा गया दिनांक",
"Format": "फॉर्मेट",
"Ascending": "आरोही",
"Descending": "अवरोही",
"Sort by...": "द्वारा क्रमबद्ध करें...",
"Added": "जोड़ा गया",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description": "विवरण",
"No description available": "कोई विवरण उपलब्ध नहीं है",
"List": "सूची",
"Grid": "ग्रिड",
"(from 'As You Like It', Act II)": "('जैसा आप इसे पसंद करते हैं', अधिनियम II)",
"Link Color": "लिंक रंग",
"Volume Keys for Page Flip": "पृष्ठ फ़्लिप के लिए वॉल्यूम कुंजियाँ",
"Screen": "स्क्रीन",
"Orientation": "अवयव",
"Portrait": "पोर्ट्रेट",
"Landscape": "लैंडस्केप",
"Open Last Book on Start": "शुरू में अंतिम पुस्तक खोलें",
"Checking for updates...": "अपडेट की जांच कर रहा है...",
"Error checking for updates": "अपडेट की जांच करते समय त्रुटि",
"Details": "विवरण",
"File Size": "फ़ाइल आकार",
"Auto Detect": "स्वचालित पहचान",
"Next Section": "अगला अनुभाग",
"Previous Section": "पिछला अनुभाग",
"Next Page": "अगला पृष्ठ",
"Previous Page": "पिछला पृष्ठ",
"Are you sure to delete {{count}} selected book(s)?_one": "क्या आप चयनित पुस्तक हटाना चाहते हैं?",
"Are you sure to delete {{count}} selected book(s)?_other": "क्या आप चयनित {{count}} पुस्तकें हटाना चाहते हैं?",
"Are you sure to delete the selected book?": "क्या आप चयनित पुस्तक हटाना चाहते हैं?",
"Deselect": "रद्द करें",
"Select All": "सब चुनें",
"No translation available.": "कोई अनुवाद उपलब्ध नहीं है।",
"Translated by {{provider}}.": "{{provider}} द्वारा अनुवादित।",
"DeepL": "डीपएल",
"Google Translate": "गूगल अनुवाद",
"Azure Translator": "एज़्योर अनुवादक",
"Invert Image In Dark Mode": "अंधेरे में छवि को उलटें",
"Help improve Readest": "Readest में सुधार करने में मदद करें",
"Sharing anonymized statistics": "सांख्यिकी साझा करना",
"Interface Language": "इंटरफ़ेस भाषा",
"Translation": "अनुवाद",
"Enable Translation": "अनुवाद सक्षम करें",
"Translation Service": "अनुवाद सेवा",
"Translate To": "अनुवाद करें",
"Disable Translation": "अनुवाद अक्षम करें",
"Scroll": "स्क्रॉल",
"Overlap Pixels": "ओवरलैप पिक्सेल",
"System Language": "सिस्टम भाषा",
"Security": "सुरक्षा",
"Allow JavaScript": "जावास्क्रिप्ट की अनुमति दें",
"Enable only if you trust the file.": "केवल तभी सक्षम करें जब आप फ़ाइल पर भरोसा करते हों।",
"Sort TOC by Page": "सामग्री को पृष्ठ द्वारा क्रमबद्ध करें",
"Search in {{count}} Book(s)..._one": "{{count}} पुस्तक में खोजें...",
"Search in {{count}} Book(s)..._other": "{{count}} पुस्तकों में खोजें...",
"No notes match your search": "कोई नोट्स नहीं मिले",
"Search notes and excerpts...": "नोट्स खोजें...",
"Sign in to Sync": "सिंक करने के लिए साइन इन करें",
"Synced at {{time}}": "{{time}} पर सिंक किया गया",
"Never synced": "कभी सिंक नहीं किया गया",
"Show Remaining Time": "शेष समय दिखाएं",
"{{time}} min left in chapter": "{{time}} मिनट शेष अध्याय में",
"Override Book Color": "पुस्तक रंग ओवरराइड करें",
"Login Required": "लॉगिन ज़रूरी",
"Quota Exceeded": "सीमा पार",
"{{percentage}}% of Daily Translation Characters Used.": "{{percentage}}% दैनिक अनुवाद वर्णों का उपयोग किया गया है।",
"Translation Characters": "अनुवाद वर्ण",
"{{engine}}: {{count}} voices_one": "{{engine}}: {{count}} आवाज़",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}} आवाज़ें",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "कुछ गलत हो गया। चिंता न करें, हमारी टीम को सूचित कर दिया गया है और हम एक समाधान पर काम कर रहे हैं।",
"Error Details:": "त्रुटि विवरण:",
"Try Again": "फिर से प्रयास करें",
"Need help?": "मदद चाहिए?",
"Contact Support": "सहायता से संपर्क करें",
"Code Highlighting": "कोड हाइलाइटिंग",
"Enable Highlighting": "हाइलाइटिंग सक्षम करें",
"Code Language": "कोड भाषा",
"Top Margin (px)": "ऊपरी हाशिया (px)",
"Bottom Margin (px)": "निचला हाशिया (px)",
"Right Margin (px)": "दायां हाशिया (px)",
"Left Margin (px)": "बायां हाशिया (px)",
"Column Gap (%)": "स्तंभों के बीच की दूरी (%)",
"Always Show Status Bar": "स्थिति पट्टी हमेशा दिखाएं",
"Custom Content CSS": "सामग्री का CSS",
"Enter CSS for book content styling...": "पुस्तक सामग्री के लिए CSS दर्ज करें...",
"Custom Reader UI CSS": "इंटरफ़ेस का CSS",
"Enter CSS for reader interface styling...": "रीडर इंटरफ़ेस के लिए CSS दर्ज करें...",
"Crop": "काटें",
"Book Covers": "पुस्तक कवर",
"Fit": "फिट",
"Reset {{settings}}": "रीसेट {{settings}}",
"Reset Settings": "सेटिंग्स रीसेट करें",
"{{count}} pages left in chapter_one": "इस अध्याय में {{count}} पृष्ठ शेष हैं",
"{{count}} pages left in chapter_other": "इस अध्याय में {{count}} पृष्ठ शेष हैं",
"Show Remaining Pages": "शेष पृष्ठ दिखाएँ",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "सदस्यता प्रबंधित करें",
"Coming Soon": "जल्द आ रहा है",
"Upgrade to {{plan}}": "{{plan}} में अपग्रेड करें",
"Upgrade to Plus or Pro": "Plus या Pro में अपग्रेड करें",
"Current Plan": "वर्तमान योजना",
"Plan Limits": "योजना की सीमाएँ",
"Processing your payment...": "आपका भुगतान संसाधित हो रहा है...",
"Please wait while we confirm your subscription.": "कृपया प्रतीक्षा करें, हम आपकी सदस्यता की पुष्टि कर रहे हैं।",
"Payment Processing": "भुगतान संसाधित हो रहा है",
"Your payment is being processed. This usually takes a few moments.": "आपका भुगतान संसाधित हो रहा है। इसमें कुछ क्षण लग सकते हैं।",
"Payment Failed": "भुगतान विफल",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "हम आपकी सदस्यता संसाधित नहीं कर सके। कृपया पुनः प्रयास करें या समस्या बने रहने पर सहायता से संपर्क करें।",
"Back to Profile": "प्रोफ़ाइल पर वापस जाएँ",
"Subscription Successful!": "सदस्यता सफल हुई!",
"Thank you for your subscription! Your payment has been processed successfully.": "आपकी सदस्यता के लिए धन्यवाद! आपका भुगतान सफलतापूर्वक संसाधित हो गया है।",
"Email:": "ईमेल:",
"Plan:": "योजना:",
"Amount:": "राशि:",
"Go to Library": "लाइब्रेरी पर जाएँ",
"Need help? Contact our support team at support@readest.com": "मदद चाहिए? हमारी सहायता टीम से संपर्क करें: support@readest.com",
"Free Plan": "मुफ्त योजना",
"month": "महीना",
"AI Translations (per day)": "AI अनुवाद (प्रतिदिन)",
"Plus Plan": "Plus योजना",
"Includes All Free Plan Benefits": "सभी मुफ्त योजना के लाभ शामिल हैं",
"Pro Plan": "Pro योजना",
"More AI Translations": "और अधिक AI अनुवाद",
"Complete Your Subscription": "अपनी सदस्यता पूरी करें",
"{{percentage}}% of Cloud Sync Space Used.": "{{percentage}}% क्लाउड सिंक स्पेस का उपयोग किया गया है।",
"Cloud Sync Storage": "क्लाउड सिंक स्टोरेज",
"Disable": "अक्षम करें",
"Enable": "सक्षम करें",
"Upgrade to Readest Premium": "Readest प्रीमियम में अपग्रेड करें",
"Show Source Text": "मूल पाठ दिखाएं",
"Cross-Platform Sync": "क्रॉस-प्लेटफ़ॉर्म सिंक",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "सभी डिवाइस पर लाइब्रेरी, प्रगति और नोट सिंक करें।",
"Customizable Reading": "अनुकूलन योग्य पढ़ाई",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "फॉन्ट, लेआउट और थीम अपनी पसंद से बदलें।",
"AI Read Aloud": "एआई वाचन",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "प्राकृतिक एआई आवाज़ों में किताबें सुनें।",
"AI Translations": "एआई अनुवाद",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Google, Azure या DeepL से तुरंत अनुवाद करें।",
"Connect with fellow readers and get help fast in our friendly community channels.": "समुदाय से जुड़ें और सहायता पाएं।",
"Unlimited AI Read Aloud Hours": "असीमित एआई वाचन",
"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 प्रो एक्सेस",
"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": "सभी प्लस प्लान लाभ शामिल",
"Early Feature Access": "नई सुविधाओं की पहले पहुंच",
"Be the first to explore new features, updates, and innovations before anyone else.": "नई सुविधाएं, अपडेट और नवाचार सबसे पहले देखें।",
"Advanced AI Tools": "उन्नत AI उपकरण",
"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 लाख तक अक्षर अनुवाद करें।",
"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}}",
"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": "इस अध्याय में {{number}} पृष्ठ शेष हैं",
"Device": "डिवाइस",
"E-Ink Mode": "ई-इंक मोड",
"Highlight Colors": "हाइलाइट रंग",
"Auto Screen Brightness": "स्वचालित स्क्रीन ब्राइटनेस",
"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": "फुटर टॉगल करने के लिए टैप करें",
"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": "अध्याय चुनें",
"{{number}} WPM": "{{number}} WPM",
"Context": "संदर्भ",
"Ready": "तैयार",
"Chapter Progress": "अध्याय प्रगति",
"words": "शब्द",
"{{time}} left": "{{time}} शेष",
"Reading progress": "पठन प्रगति",
"Click to seek": "सीक करने के लिए क्लिक करें",
"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)",
"Pause:": "विराम:",
"Decrease speed": "गति कम करें",
"Slower (Left/Down)": "धीमी (Left/Down)",
"Current speed": "वर्तमान गति",
"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": "टीटीएस स्थान पर वापस जाएं"
}
@@ -5,11 +5,9 @@
"Animation": "Animasi",
"Annotate": "Anotasi",
"Apply": "Terapkan",
"Are you sure to delete the selected books?": "Apakah Anda yakin ingin menghapus buku yang dipilih?",
"Auto Mode": "Mode Otomatis",
"Behavior": "Perilaku",
"Book": "Buku",
"Book Cover": "Sampul Buku",
"Bookmark": "Penanda",
"Cancel": "Batal",
"Chapter": "Bab",
@@ -19,7 +17,6 @@
"Confirm Deletion": "Konfirmasi Penghapusan",
"Copied to notebook": "Disalin ke buku catatan",
"Copy": "Salin",
"Custom CSS": "CSS Kustom",
"Dark Mode": "Mode Gelap",
"Default": "Default",
"Default Font": "Font Default",
@@ -27,10 +24,8 @@
"Delete": "Hapus",
"Delete Highlight": "Hapus Sorotan",
"Dictionary": "Kamus",
"Disable Click-to-Flip": "Nonaktifkan Klik untuk Membalik",
"Download Readest": "Unduh Readest",
"Edit": "Edit",
"Enter your custom CSS here...": "Masukkan CSS kustom Anda di sini...",
"Excerpts": "Kutipan",
"Failed to import book(s): {{filenames}}": "Gagal mengimpor buku: {{filenames}}",
"Fast": "Cepat",
@@ -43,17 +38,13 @@
"Global Settings": "Pengaturan Global",
"Go Back": "Kembali",
"Go Forward": "Maju",
"Go Left": "Ke Kiri",
"Go Right": "Ke Kanan",
"Grass": "Rumput",
"Gray": "Abu-abu",
"Gruvbox": "Gruvbox",
"Highlight": "Sorot",
"Horizontal Direction": "Arah Horizontal",
"Hyphenation": "Pemenggalan Kata",
"Identifier:": "Pengenal:",
"Import Books": "Impor Buku",
"Language:": "Bahasa:",
"Layout": "Tata Letak",
"Light Mode": "Mode Terang",
"Loading...": "Memuat...",
@@ -64,7 +55,6 @@
"Match Whole Words": "Cocokkan Kata Utuh",
"Maximum Number of Columns": "Jumlah Kolom Maksimum",
"Minimum Font Size": "Ukuran Font Minimum",
"Misc": "Lain-lain",
"Monospace Font": "Font Monospace",
"More Info": "Info Lebih Lanjut",
"Nord": "Nord",
@@ -76,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",
@@ -91,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",
@@ -102,17 +91,15 @@
"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:",
"User avatar": "Avatar Pengguna",
"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.",
@@ -121,26 +108,21 @@
"Your Library": "Perpustakaan Anda",
"TTS not supported for PDF": "TTS tidak didukung untuk PDF",
"Override Book Font": "Ganti Font Buku",
"Vertical Margins (px)": "Margin Vertikal (px)",
"Horizontal Margins (%)": "Margin Horizontal (%)",
"Apply to All Books": "Terapkan ke semua buku",
"Apply to This Book": "Terapkan ke buku ini",
"Unable to fetch the translation. Try again later.": "Tidak dapat mengambil terjemahan. Coba lagi nanti.",
"Update Now!": "Perbarui Sekarang!",
"Update": "Perbarui",
"Check Update": "Periksa pembaruan",
"Already the latest version": "Sudah versi terbaru",
"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}}",
"Failed to download book: {{title}}": "Gagal mengunduh buku: {{title}}",
"Upload Book": "Unggah Buku",
"Auto Upload Books to Cloud": "Unggah Buku Otomatis ke Cloud",
"{{percentage}}% of Cloud Storage Used.": "{{percentage}}% dari Penyimpanan Cloud Digunakan.",
"Storage": "Penyimpanan",
"Book deleted: {{title}}": "Buku dihapus: {{title}}",
"Failed to delete book: {{title}}": "Gagal menghapus buku: {{title}}",
"Check Updates on Start": "Periksa Pembaruan saat Memulai",
@@ -172,7 +154,7 @@
"Create a Password": "Buat kata sandi",
"Sign up": "Daftar",
"Signing up...": "Sedang mendaftar...",
"Dont have an account? Sign up": "Belum punya akun? Daftar",
"Don't have an account? Sign up": "Belum punya akun? Daftar",
"Check your email for the confirmation link": "Periksa email Anda untuk tautan konfirmasi",
"Signing in ...": "Sedang masuk ...",
"Send a magic link email": "Kirim email tautan ajaib",
@@ -191,41 +173,15 @@
"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",
"Cloud Storage": "Penyimpanan Cloud",
"Failed to delete user. Please try again later.": "Gagal menghapus pengguna. Silakan coba lagi nanti.",
"Unlimited Offline/Online Reading": "Membaca Offline/Online Tanpa Batas",
"Unlimited Cloud Sync Devices": "Perangkat Sinkronisasi Cloud Tanpa Batas",
"Essential Text-to-Speech Voices": "Suara Text-to-Speech Esensial",
"DeepL Free Access": "Akses DeepL Gratis",
"Community Support": "Dukungan Komunitas",
"500 MB Cloud Sync Space": "Ruang Sinkronisasi Cloud 500 MB",
"Includes All Free Tier Benefits": "Termasuk Semua Manfaat Tingkat Gratis",
"AI Summaries": "Ringkasan AI",
"AI Translations": "Terjemahan AI",
"Priority Support": "Dukungan Prioritas",
"DeepL Pro Access": "Akses DeepL Pro",
"Expanded Text-to-Speech Voices": "Suara Text-to-Speech yang Diperluas",
"2000 MB Cloud Sync Space": "Ruang Sinkronisasi Cloud 2000 MB",
"Includes All Plus Tier Benefits": "Termasuk Semua Manfaat Tingkat Plus",
"Unlimited AI Summaries": "Ringkasan AI Tanpa Batas",
"Unlimited AI Translations": "Terjemahan AI Tanpa Batas",
"Unlimited DeepL Pro Access": "Akses DeepL Pro Tanpa Batas",
"Advanced AI Tools": "Alat AI Lanjutan",
"Early Feature Access": "Akses Fitur Awal",
"10 GB Cloud Sync Space": "Ruang Sinkronisasi Cloud 10 GB",
"Loading profile...": "Memuat profil...",
"Features": "Fitur",
"Delete Account": "Hapus Akun",
"Delete Your Account?": "Hapus Akun Anda?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "Tindakan ini tidak dapat dibatalkan. Semua data Anda di cloud akan dihapus secara permanen.",
"Delete Permanently": "Hapus Secara Permanen",
"Free Tier": "Tingkat Gratis",
"Plus Tier": "Tingkat Plus",
"Pro Tier": "Tingkat Pro",
"RTL Direction": "Arah RTL",
"Maximum Column Height": "Tinggi Kolom Maksimum",
"Maximum Column Width": "Lebar Kolom Maksimum",
@@ -234,7 +190,7 @@
"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",
@@ -259,11 +215,809 @@
"Copied to clipboard": "Disalin ke papan klip",
"Export Annotations": "Ekspor Anotasi",
"Auto Import on File Open": "Impor Otomatis saat File Dibuka",
"LXGW WenKai GB Screen": "LXGW WenKai",
"Swap Click-to-Flip Area": "Tukar Area Klik untuk Membalik",
"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.",
"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",
"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"
"Group": "Grup",
"Always on Top": "Selalu di Atas",
"No Timeout": "Tidak Ada Waktu Habis",
"{{value}} minute": "{{value}} menit",
"{{value}} minutes": "{{value}} menit",
"{{value}} hour": "{{value}} jam",
"{{value}} hours": "{{value}} jam",
"CJK Font": "Font CJK",
"Clear Search": "Hapus Pencarian",
"Header & Footer": "Header & Footer",
"Apply also in Scrolled Mode": "Terapkan juga di Mode Gulir",
"A new version of Readest is available!": "Versi baru Readest Tersedia!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} tersedia (versi terinstal {{currentVersion}}).",
"Download and install now?": "Unduh dan instal sekarang?",
"Downloading {{downloaded}} of {{contentLength}}": "Mengunduh {{downloaded}} dari {{contentLength}}",
"Download finished": "Unduhan selesai",
"DOWNLOAD & INSTALL": "UNDUH & INSTAL",
"Changelog": "Catatan Perubahan",
"Software Update": "Pembaruan Perangkat Lunak",
"Title": "Judul",
"Date Read": "Tanggal Dibaca",
"Date Added": "Tanggal Ditambahkan",
"Format": "Format",
"Ascending": "Naik",
"Descending": "Turun",
"Sort by...": "Urutkan berdasarkan...",
"Added": "Ditambahkan",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"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",
"Screen": "Screen",
"Orientation": "Orientasi",
"Portrait": "Potret",
"Landscape": "Lanskap",
"Open Last Book on Start": "Buka Buku Terakhir saat Memulai",
"Checking for updates...": "Memeriksa pembaruan...",
"Error checking for updates": "Kesalahan saat memeriksa pembaruan",
"Details": "Detail",
"File Size": "Ukuran File",
"Auto Detect": "Deteksi Otomatis",
"Next Section": "Bagian Selanjutnya",
"Previous Section": "Bagian Sebelumnya",
"Next Page": "Halaman Berikutnya",
"Previous Page": "Halaman Sebelumnya",
"Are you sure to delete {{count}} selected book(s)?_other": "Apakah Anda yakin ingin menghapus {{count}} buku yang dipilih?",
"Are you sure to delete the selected book?": "Apakah Anda yakin ingin menghapus buku yang dipilih?",
"Deselect": "Batal",
"Select All": "Pilih Semua",
"No translation available.": "Tidak ada terjemahan yang tersedia.",
"Translated by {{provider}}.": "Terjemahan oleh {{provider}}.",
"DeepL": "DeepL",
"Google Translate": "Google Translate",
"Azure Translator": "Azure Translator",
"Invert Image In Dark Mode": "Inversi Gambar di Gelap",
"Help improve Readest": "Bantu tingkatkan Readest",
"Sharing anonymized statistics": "Berbagi statistik anonim",
"Interface Language": "Bahasa Antarmuka",
"Translation": "Terjemahan",
"Enable Translation": "Aktifkan Terjemahan",
"Translation Service": "Layanan Terjemahan",
"Translate To": "Terjemahkan Ke",
"Disable Translation": "Nonaktifkan Terjemahan",
"Scroll": "Scroll",
"Overlap Pixels": "Overlap Piksel",
"System Language": "Bahasa Sistem",
"Security": "Keamanan",
"Allow JavaScript": "Izinkan JavaScript",
"Enable only if you trust the file.": "Aktifkan hanya jika Anda mempercayai file tersebut.",
"Sort TOC by Page": "Urutkan TOC berdasarkan Halaman",
"Search in {{count}} Book(s)..._other": "Cari di {{count}} Buku...",
"No notes match your search": "Tidak ada catatan ditemukan",
"Search notes and excerpts...": "Cari catatan...",
"Sign in to Sync": "Masuk untuk Sinkronisasi",
"Synced at {{time}}": "Disinkronkan pada {{time}}",
"Never synced": "Belum pernah disinkronkan",
"Show Remaining Time": "Perlihatkan Waktu Tersisa",
"{{time}} min left in chapter": "{{time}} menit tersisa di bab",
"Override Book Color": "Ubah Warna Buku",
"Login Required": "Perlu masuk",
"Quota Exceeded": "Kuota terlampaui",
"{{percentage}}% of Daily Translation Characters Used.": "{{percentage}}% dari Karakter Terjemahan Harian Digunakan.",
"Translation Characters": "Karakter Terjemahan",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}} suara",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "Terjadi kesalahan. Jangan khawatir, tim kami telah diberitahu dan kami sedang bekerja untuk memperbaikinya.",
"Error Details:": "Rincian Kesalahan:",
"Try Again": "Coba Lagi",
"Need help?": "Butuh bantuan?",
"Contact Support": "Hubungi Dukungan",
"Code Highlighting": "Penyorotan Kode",
"Enable Highlighting": "Aktifkan Penyorotan",
"Code Language": "Bahasa Kode",
"Top Margin (px)": "Margin Atas (px)",
"Bottom Margin (px)": "Margin Bawah (px)",
"Right Margin (px)": "Margin Kanan (px)",
"Left Margin (px)": "Margin Kiri (px)",
"Column Gap (%)": "Jarak Antar Kolom (%)",
"Always Show Status Bar": "Selalu Tampilkan Bilah Status",
"Custom Content CSS": "CSS konten",
"Enter CSS for book content styling...": "Masukkan CSS untuk gaya konten buku...",
"Custom Reader UI CSS": "CSS antarmuka",
"Enter CSS for reader interface styling...": "Masukkan CSS untuk gaya antarmuka pembaca...",
"Crop": "Potong",
"Book Covers": "Sampul Buku",
"Fit": "Pas",
"Reset {{settings}}": "Atur Ulang {{settings}}",
"Reset Settings": "Atur Ulang Pengaturan",
"{{count}} pages left in chapter_other": "{{count}} halaman tersisa di bab ini",
"Show Remaining Pages": "Tampilkan halaman tersisa",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Kelola Langganan",
"Coming Soon": "Segera Hadir",
"Upgrade to {{plan}}": "Tingkatkan ke {{plan}}",
"Upgrade to Plus or Pro": "Tingkatkan ke Plus atau Pro",
"Current Plan": "Paket Saat Ini",
"Plan Limits": "Batas Paket",
"Processing your payment...": "Memproses pembayaran Anda...",
"Please wait while we confirm your subscription.": "Mohon tunggu saat kami mengonfirmasi langganan Anda.",
"Payment Processing": "Memproses Pembayaran",
"Your payment is being processed. This usually takes a few moments.": "Pembayaran Anda sedang diproses. Ini biasanya memerlukan beberapa saat.",
"Payment Failed": "Pembayaran Gagal",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "Kami tidak dapat memproses langganan Anda. Silakan coba lagi atau hubungi dukungan jika masalah berlanjut.",
"Back to Profile": "Kembali ke Profil",
"Subscription Successful!": "Langganan Berhasil!",
"Thank you for your subscription! Your payment has been processed successfully.": "Terima kasih atas langganan Anda! Pembayaran Anda telah berhasil diproses.",
"Email:": "Email:",
"Plan:": "Paket:",
"Amount:": "Jumlah:",
"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",
"month": "bulan",
"AI Translations (per day)": "Terjemahan AI (per hari)",
"Plus Plan": "Paket Plus",
"Includes All Free Plan Benefits": "Termasuk Semua Manfaat Paket Gratis",
"Pro Plan": "Paket Pro",
"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": "Penyimpanan Sinkronisasi Cloud",
"Disable": "Nonaktifkan",
"Enable": "Aktifkan",
"Upgrade to Readest Premium": "Tingkatkan ke Readest Premium",
"Show Source Text": "Perlihatkan Teks Sumber",
"Cross-Platform Sync": "Sinkronisasi Lintas Platform",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "Sinkronkan pustaka, kemajuan, dan catatan di semua perangkat Anda.",
"Customizable Reading": "Membaca yang Dapat Disesuaikan",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "Atur font, tata letak, dan tema sesuai keinginan.",
"AI Read Aloud": "Pembacaan AI",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "Dengarkan buku dengan suara AI alami.",
"AI Translations": "Terjemahan AI",
"Connect with fellow readers and get help fast in our friendly community channels.": "Terhubung dengan komunitas dan dapatkan bantuan cepat.",
"Unlimited AI Read Aloud Hours": "Waktu Baca AI Tanpa Batas",
"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",
"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.",
"Includes All Plus Plan Benefits": "Termasuk Semua Manfaat Paket Plus",
"Early Feature Access": "Akses Fitur Lebih Awal",
"Be the first to explore new features, updates, and innovations before anyone else.": "Jadi yang pertama menjelajahi fitur baru, pembaruan, dan inovasi.",
"Advanced AI Tools": "Alat AI Canggih",
"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.",
"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}}",
"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": "{{number}} halaman tersisa di bab",
"Device": "Perangkat",
"E-Ink Mode": "Mode E-Ink",
"Highlight Colors": "Warna Sorotan",
"Auto Screen Brightness": "Auto Kecerahan Layar",
"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",
"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",
"{{number}} WPM": "{{number}} WPM",
"Context": "Konteks",
"Ready": "Siap",
"Chapter Progress": "Kemajuan Bab",
"words": "kata",
"{{time}} left": "{{time}} tersisa",
"Reading progress": "Kemajuan membaca",
"Click to seek": "Klik untuk mencari",
"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)",
"Pause:": "Jeda:",
"Decrease speed": "Kurangi kecepatan",
"Slower (Left/Down)": "Lebih lambat (Kiri/Bawah)",
"Current speed": "Kecepatan saat ini",
"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"
}
File diff suppressed because it is too large Load Diff
@@ -5,11 +5,9 @@
"Animation": "アニメーション",
"Annotate": "注釈",
"Apply": "適用",
"Are you sure to delete the selected books?": "選択した書籍を削除してもよろしいですか?",
"Auto Mode": "自動モード",
"Behavior": "動作",
"Book": "書籍",
"Book Cover": "表紙",
"Bookmark": "ブックマーク",
"Cancel": "キャンセル",
"Chapter": "章",
@@ -19,7 +17,6 @@
"Confirm Deletion": "削除の確認",
"Copied to notebook": "ノートブックにコピー",
"Copy": "コピー",
"Custom CSS": "カスタムCSS",
"Dark Mode": "ダークモード",
"Default": "デフォルト",
"Default Font": "デフォルトフォント",
@@ -27,10 +24,8 @@
"Delete": "削除",
"Delete Highlight": "ハイライトを削除",
"Dictionary": "辞書",
"Disable Click-to-Flip": "クリックめくりを無効化",
"Download Readest": "Readestをダウンロード",
"Edit": "編集",
"Enter your custom CSS here...": "ここにカスタムCSSを入力...",
"Excerpts": "抜粋",
"Failed to import book(s): {{filenames}}": "書籍のインポートに失敗しました:{{filenames}}",
"Fast": "高速",
@@ -43,17 +38,13 @@
"Global Settings": "全体設定",
"Go Back": "戻る",
"Go Forward": "進む",
"Go Left": "左へ",
"Go Right": "右へ",
"Grass": "グリーン",
"Gray": "グレー",
"Gruvbox": "グルーブボックス",
"Highlight": "ハイライト",
"Horizontal Direction": "横書",
"Hyphenation": "ハイフネーション",
"Identifier:": "識別子:",
"Import Books": "書籍をインポート",
"Language:": "言語:",
"Layout": "レイアウト",
"Light Mode": "ライトモード",
"Loading...": "読み込み中...",
@@ -64,7 +55,6 @@
"Match Whole Words": "単語全体を一致",
"Maximum Number of Columns": "最大列数",
"Minimum Font Size": "最小フォントサイズ",
"Misc": "その他",
"Monospace Font": "等幅フォント",
"More Info": "詳細情報",
"Nord": "ノルド",
@@ -76,8 +66,8 @@
"Paging Animation": "ページめくりアニメーション",
"Paragraph": "段落",
"Parallel Read": "並列読書",
"Published:": "出版日",
"Publisher:": "出版社",
"Published": "出版日",
"Publisher": "出版社",
"Reading Progress Synced": "読書進捗が同期されました",
"Reload Page": "ページを再読み込み",
"Reveal in File Explorer": "エクスプローラーで表示",
@@ -91,7 +81,6 @@
"Search...": "検索...",
"Select Book": "書籍を選択",
"Select Books": "書籍を選択",
"Select Multiple Books": "複数の書籍を選択",
"Sepia": "セピア",
"Serif Font": "セリフ体",
"Show Book Details": "書籍の詳細を表示",
@@ -102,17 +91,15 @@
"Slow": "低速",
"Solarized": "ソーラライズド",
"Speak": "読み上げ",
"Subjects:": "主題",
"Subjects": "主題",
"System Fonts": "システムフォント",
"TTS not supported in this device": "このデバイスではTTSがサポートされていません",
"Theme Color": "テーマカラー",
"Theme Mode": "テーマモード",
"Translate": "翻訳",
"Translated Text": "翻訳されたテキスト",
"Unknown": "不明",
"Untitled": "無題",
"Updated:": "更新日",
"User avatar": "ユーザーアバター",
"Updated": "更新日",
"Version {{version}}": "バージョン {{version}}",
"Vertical Direction": "縦書",
"Welcome to your library. You can import your books here and read them anytime.": "ライブラリーへようこそ。ここに書籍をインポートして、いつでも読むことができます。",
@@ -121,26 +108,21 @@
"Your Library": "ライブラリー",
"TTS not supported for PDF": "PDFではTTSがサポートされていません",
"Override Book Font": "書籍フォントを上書き",
"Vertical Margins (px)": "縦マージン(px",
"Horizontal Margins (%)": "横マージン(%",
"Apply to All Books": "すべての書籍に適用",
"Apply to This Book": "この書籍に適用",
"Unable to fetch the translation. Try again later.": "翻訳を取得できません。後で再試行してください。",
"Update Now!": "今すぐ更新!",
"Update": "更新",
"Check Update": "更新を確認",
"Already the latest version": "すでに最新バージョン",
"Book Details": "書籍の詳細",
"From Local File": "ローカルファイルから",
"TOC": "目次",
"Table of Contents": "目次",
"Book uploaded: {{title}}": "書籍がアップロードされました:{{title}}",
"Failed to upload book: {{title}}": "書籍のアップロードに失敗しました:{{title}}",
"Book downloaded: {{title}}": "書籍がダウンロードされました:{{title}}",
"Failed to download book: {{title}}": "書籍のダウンロードに失敗しました:{{title}}",
"Upload Book": "書籍をアップロード",
"Auto Upload Books to Cloud": "書籍を自動的にクラウドにアップロード",
"{{percentage}}% of Cloud Storage Used.": "クラウドストレージの{{percentage}}%が使用されています。",
"Storage": "ストレージ",
"Book deleted: {{title}}": "書籍が削除されました:{{title}}",
"Failed to delete book: {{title}}": "書籍の削除に失敗しました:{{title}}",
"Check Updates on Start": "開始時に更新を確認",
@@ -172,7 +154,7 @@
"Create a Password": "パスワードを作成",
"Sign up": "サインアップ",
"Signing up...": "サインアップ中...",
"Dont have an account? Sign up": "アカウントをお持ちでないですか? サインアップ",
"Don't have an account? Sign up": "アカウントをお持ちでないですか? サインアップ",
"Check your email for the confirmation link": "確認リンクのためにメールを確認してください",
"Signing in ...": "サインイン中 ...",
"Send a magic link email": "マジックリンクメールを送信",
@@ -191,41 +173,15 @@
"Token": "トークン",
"Your OTP token": "あなたのOTPトークン",
"Verify token": "トークンを確認",
"Sign in with Google": "Googleでサインイン",
"Sign in with Apple": "Appleでサインイン",
"Sign in with GitHub": "GitHubでサインイン",
"Account": "アカウント",
"Cloud Storage": "クラウドストレージ",
"Failed to delete user. Please try again later.": "ユーザーの削除に失敗しました。後ほど再試行してください。",
"Unlimited Offline/Online Reading": "無制限のオフライン/オンライン読書",
"Unlimited Cloud Sync Devices": "無制限のクラウド同期デバイス",
"Essential Text-to-Speech Voices": "基本的な音声合成ボイス",
"DeepL Free Access": "DeepL無料アクセス",
"Community Support": "コミュニティサポート",
"500 MB Cloud Sync Space": "500 MBのクラウド同期スペース",
"Includes All Free Tier Benefits": "無料プランの全特典を含む",
"AI Summaries": "AI要約",
"AI Translations": "AI翻訳",
"Priority Support": "優先サポート",
"DeepL Pro Access": "DeepL Proアクセス",
"Expanded Text-to-Speech Voices": "拡張された音声合成ボイス",
"2000 MB Cloud Sync Space": "2000 MBのクラウド同期スペース",
"Includes All Plus Tier Benefits": "Plusプランの全特典を含む",
"Unlimited AI Summaries": "無制限のAI要約",
"Unlimited AI Translations": "無制限のAI翻訳",
"Unlimited DeepL Pro Access": "無制限のDeepL Proアクセス",
"Advanced AI Tools": "高度なAIツール",
"Early Feature Access": "新機能への早期アクセス",
"10 GB Cloud Sync Space": "10 GBのクラウド同期スペース",
"Loading profile...": "プロフィール読み込み中...",
"Features": "機能",
"Delete Account": "アカウント削除",
"Delete Your Account?": "アカウントを削除しますか?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "この操作は元に戻せません。クラウド上のすべてのデータが完全に削除されます。",
"Delete Permanently": "完全に削除",
"Free Tier": "無料プラン",
"Plus Tier": "Plusプラン",
"Pro Tier": "Proプラン",
"RTL Direction": "RTL方向",
"Maximum Column Height": "最大列高",
"Maximum Column Width": "最大列幅",
@@ -234,7 +190,7 @@
"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": "テキストカラー",
@@ -259,11 +215,809 @@
"Copied to clipboard": "クリップボードにコピー",
"Export Annotations": "注釈をエクスポート",
"Auto Import on File Open": "ファイルを開くと自動インポート",
"LXGW WenKai GB Screen": "LXGW WenKai",
"Swap Click-to-Flip Area": "クリックめくりエリアを入れ替え",
"No chapters detected.": "章が検出されません",
"Failed to parse the EPUB file.": "EPUBファイルの解析に失敗しました",
"This book format is not supported.": "この書籍形式はサポートされていません",
"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": "この書籍形式はサポートされていません",
"Unable to fetch the translation. Please log in first and try again.": "翻訳を取得できません。まずログインして再試行してください。",
"Group": "グループ"
"Group": "グループ",
"Always on Top": "常に最前面",
"No Timeout": "タイムアウトなし",
"{{value}} minute": "{{value}}分",
"{{value}} minutes": "{{value}}分",
"{{value}} hour": "{{value}}時間",
"{{value}} hours": "{{value}}時間",
"CJK Font": "CJKフォント",
"Clear Search": "検索をクリア",
"Header & Footer": "ヘッダーとフッター",
"Apply also in Scrolled Mode": "スクロールモードでも適用",
"A new version of Readest is available!": "新しいバージョンのReadestが利用可能です!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}}が利用可能です(インストールされたバージョン{{currentVersion}})。",
"Download and install now?": "今すぐダウンロードしてインストールしますか?",
"Downloading {{downloaded}} of {{contentLength}}": "ダウンロード中 {{downloaded}} / {{contentLength}}",
"Download finished": "ダウンロード完了",
"DOWNLOAD & INSTALL": "更新",
"Changelog": "変更ログ",
"Software Update": "ソフトウェアの更新",
"Title": "タイトル",
"Date Read": "読書日",
"Date Added": "追加日",
"Format": "形式",
"Ascending": "昇順",
"Descending": "降順",
"Sort by...": "並べ替え...",
"Added": "追加日",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description": "説明",
"No description available": "説明はありません",
"List": "リスト",
"Grid": "グリッド",
"(from 'As You Like It', Act II)": "(「お気に召すまま」第2幕)",
"Link Color": "リンクカラー",
"Volume Keys for Page Flip": "音量キーでページめくり",
"Screen": "画面",
"Orientation": "向き",
"Portrait": "縦",
"Landscape": "横",
"Open Last Book on Start": "開始時に最後の書籍を開く",
"Checking for updates...": "更新を確認中...",
"Error checking for updates": "更新の確認中にエラーが発生しました",
"Details": "詳細",
"File Size": "ファイルサイズ",
"Auto Detect": "自動検出",
"Next Section": "次のセクション",
"Previous Section": "前のセクション",
"Next Page": "次のページ",
"Previous Page": "前のページ",
"Are you sure to delete {{count}} selected book(s)?_other": "選択した{{count}}冊の本を削除してもよろしいですか?",
"Are you sure to delete the selected book?": "選択した本を削除してもよろしいですか?",
"Deselect": "解除",
"Select All": "全選択",
"No translation available.": "翻訳はありません。",
"Translated by {{provider}}.": "{{provider}}によって翻訳されました。",
"DeepL": "DeepL",
"Google Translate": "Google翻訳",
"Azure Translator": "Azure翻訳",
"Invert Image In Dark Mode": "ダークモードで画像を反転",
"Help improve Readest": "Readestを改善する手助け",
"Sharing anonymized statistics": "匿名化された統計情報を共有",
"Interface Language": "インターフェースの言語",
"Translation": "翻訳",
"Enable Translation": "翻訳を有効にする",
"Translation Service": "翻訳サービス",
"Translate To": "翻訳先",
"Disable Translation": "翻訳を無効にする",
"Scroll": "スクロール",
"Overlap Pixels": "重なりピクセル",
"System Language": "システム言語",
"Security": "セキュリティ",
"Allow JavaScript": "JavaScriptを許可",
"Enable only if you trust the file.": "ファイルを信頼する場合にのみ有効にしてください。",
"Sort TOC by Page": "目次をページで並べ替え",
"Search in {{count}} Book(s)..._other": "{{count}}冊の本を検索...",
"No notes match your search": "ノートが見つかりません",
"Search notes and excerpts...": "ノートを検索...",
"Sign in to Sync": "同期するにはサインイン",
"Synced at {{time}}": "{{time}} に同期済み",
"Never synced": "まだ同期されていません",
"Show Remaining Time": "残り時間を表示",
"{{time}} min left in chapter": "{{time}}分残り",
"Override Book Color": "書籍の色を上書き",
"Login Required": "ログイン必須",
"Quota Exceeded": "上限超過",
"{{percentage}}% of Daily Translation Characters Used.": "日次翻訳文字数の使用量は{{percentage}}%です。",
"Translation Characters": "翻訳文字数",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}}音声",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "何か問題が発生しました。心配しないでください。私たちのチームが通知を受けており、修正に取り組んでいます。",
"Error Details:": "エラーの詳細:",
"Try Again": "再試行",
"Need help?": "ヘルプが必要ですか?",
"Contact Support": "サポートに連絡",
"Code Highlighting": "コードハイライト",
"Enable Highlighting": "ハイライトを有効にする",
"Code Language": "コード言語",
"Top Margin (px)": "上マージン (px)",
"Bottom Margin (px)": "下マージン (px)",
"Right Margin (px)": "右マージン (px)",
"Left Margin (px)": "左マージン (px)",
"Column Gap (%)": "列間の間隔 (%)",
"Always Show Status Bar": "ステータスバーを常に表示",
"Custom Content CSS": "コンテンツCSS",
"Enter CSS for book content styling...": "本のコンテンツ用CSSを入力...",
"Custom Reader UI CSS": "リーダーUIのCSS",
"Enter CSS for reader interface styling...": "リーダーインターフェース用CSSを入力...",
"Crop": "トリミング",
"Book Covers": "書籍の表紙",
"Fit": "フィット",
"Reset {{settings}}": "{{settings}}をリセット",
"Reset Settings": "設定をリセット",
"{{count}} pages left in chapter_other": "{{count}} ページ残り",
"Show Remaining Pages": "残りを表示",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "サブスクリプションを管理",
"Coming Soon": "近日公開",
"Upgrade to {{plan}}": "{{plan}} にアップグレード",
"Upgrade to Plus or Pro": "Plus または Pro にアップグレード",
"Current Plan": "現在のプラン",
"Plan Limits": "プランの上限",
"Processing your payment...": "お支払いを処理中...",
"Please wait while we confirm your subscription.": "サブスクリプションを確認しています。しばらくお待ちください。",
"Payment Processing": "支払いを処理中",
"Your payment is being processed. This usually takes a few moments.": "お支払いを処理しています。通常、数秒かかります。",
"Payment Failed": "支払いに失敗しました",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "サブスクリプションを処理できませんでした。再度お試しいただくか、問題が続く場合はサポートにお問い合わせください。",
"Back to Profile": "プロフィールに戻る",
"Subscription Successful!": "サブスクリプションが完了しました!",
"Thank you for your subscription! Your payment has been processed successfully.": "ご登録ありがとうございます!お支払いが正常に処理されました。",
"Email:": "メール:",
"Plan:": "プラン:",
"Amount:": "金額:",
"Go to Library": "ライブラリへ移動",
"Need help? Contact our support team at support@readest.com": "サポートが必要ですか? support@readest.com までお問い合わせください。",
"Free Plan": "無料プラン",
"month": "月",
"AI Translations (per day)": "AI翻訳(1日あたり)",
"Plus Plan": "Plusプラン",
"Includes All Free Plan Benefits": "無料プランの全特典を含む",
"Pro Plan": "Proプラン",
"More AI Translations": "さらに多くのAI翻訳",
"Complete Your Subscription": "サブスクリプションを完了する",
"{{percentage}}% of Cloud Sync Space Used.": "クラウド同期スペースの使用量は{{percentage}}%です。",
"Cloud Sync Storage": "クラウド同期容量",
"Disable": "無効にする",
"Enable": "有効にする",
"Upgrade to Readest Premium": "Readest Premiumにアップグレード",
"Show Source Text": "原文を表示",
"Cross-Platform Sync": "クロスプラットフォーム同期",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "ライブラリや進捗、メモを全デバイスで同期。",
"Customizable Reading": "カスタマイズ可能な読書",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "フォントやレイアウト、テーマを自由に調整。",
"AI Read Aloud": "AI音声読み上げ",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "自然なAI音声で本を聴く。",
"AI Translations": "AI翻訳",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Google、Azure、DeepLで即時翻訳。",
"Connect with fellow readers and get help fast in our friendly community channels.": "コミュニティで交流・サポートを利用。",
"Unlimited AI Read Aloud Hours": "無制限のAI読み上げ",
"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利用",
"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プランの全特典を含む",
"Early Feature Access": "新機能への先行アクセス",
"Be the first to explore new features, updates, and innovations before anyone else.": "新機能、アップデート、革新を誰よりも先に体験。",
"Advanced AI Tools": "高度なAIツール",
"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万文字を翻訳。",
"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}}",
"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": "章に{{number}}ページ残り",
"Device": "デバイス",
"E-Ink Mode": "E-Inkモード",
"Highlight Colors": "ハイライトカラー",
"Auto Screen Brightness": "自動画面の明るさ",
"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": "タップでフッターを切り替え",
"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": "章を選択",
"{{number}} WPM": "{{number}} WPM",
"Context": "コンテキスト",
"Ready": "準備完了",
"Chapter Progress": "章の進捗",
"words": "単語",
"{{time}} left": "残り {{time}}",
"Reading progress": "読書の進捗",
"Click to seek": "クリックしてシーク",
"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+右)",
"Pause:": "一時停止:",
"Decrease speed": "速度を下げる",
"Slower (Left/Down)": "低速 (左/下)",
"Current speed": "現在の速度",
"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の位置に戻る"
}
@@ -5,11 +5,9 @@
"Animation": "애니메이션",
"Annotate": "주석",
"Apply": "적용",
"Are you sure to delete the selected books?": "선택한 책을 삭제하시겠습니까?",
"Auto Mode": "자동 모드",
"Behavior": "동작",
"Book": "책",
"Book Cover": "책 표지",
"Bookmark": "북마크",
"Cancel": "취소",
"Chapter": "챕터",
@@ -19,7 +17,6 @@
"Confirm Deletion": "삭제 확인",
"Copied to notebook": "노트북에 복사됨",
"Copy": "복사",
"Custom CSS": "사용자 정의 CSS",
"Dark Mode": "다크 모드",
"Default": "기본값",
"Default Font": "기본 글꼴",
@@ -27,10 +24,8 @@
"Delete": "삭제",
"Delete Highlight": "하이라이트 삭제",
"Dictionary": "사전",
"Disable Click-to-Flip": "클릭 넘기기 비활성화",
"Download Readest": "Readest 다운로드",
"Edit": "편집",
"Enter your custom CSS here...": "여기에 사용자 정의 CSS를 입력하세요...",
"Excerpts": "발췌",
"Failed to import book(s): {{filenames}}": "책 가져오기 실패: {{filenames}}",
"Fast": "빠름",
@@ -43,17 +38,13 @@
"Global Settings": "전역 설정",
"Go Back": "뒤로",
"Go Forward": "앞으로",
"Go Left": "왼쪽으로",
"Go Right": "오른쪽으로",
"Grass": "잔디색",
"Gray": "회색",
"Gruvbox": "그러브박스",
"Highlight": "하이라이트",
"Horizontal Direction": "수평 방향",
"Hyphenation": "하이픈 넣기",
"Identifier:": "식별자:",
"Import Books": "책 가져오기",
"Language:": "언어:",
"Layout": "레이아웃",
"Light Mode": "라이트 모드",
"Loading...": "로딩 중...",
@@ -64,7 +55,6 @@
"Match Whole Words": "전체 단어 일치",
"Maximum Number of Columns": "최대 열 수",
"Minimum Font Size": "최소 글꼴 크기",
"Misc": "기타",
"Monospace Font": "고정폭 글꼴",
"More Info": "추가 정보",
"Nord": "노드",
@@ -76,8 +66,8 @@
"Paging Animation": "페이지 넘김 애니메이션",
"Paragraph": "단락",
"Parallel Read": "병렬 읽기",
"Published:": "출판일:",
"Publisher:": "출판사:",
"Published": "출판일",
"Publisher": "출판사",
"Reading Progress Synced": "읽기 진행 상황 동기화됨",
"Reload Page": "페이지 새로고침",
"Reveal in File Explorer": "파일 탐색기에서 표시",
@@ -91,7 +81,6 @@
"Search...": "검색...",
"Select Book": "책 선택",
"Select Books": "책 선택",
"Select Multiple Books": "여러 책 선택",
"Sepia": "세피아",
"Serif Font": "세리프체",
"Show Book Details": "책 세부 정보 표시",
@@ -102,17 +91,15 @@
"Slow": "느림",
"Solarized": "솔라라이즈드",
"Speak": "말하기",
"Subjects:": "주제:",
"Subjects": "주제",
"System Fonts": "시스템 글꼴",
"TTS not supported in this device": "이 장치에서 TTS가 지원되지 않음",
"Theme Color": "테마 색상",
"Theme Mode": "테마 모드",
"Translate": "번역",
"Translated Text": "번역된 텍스트",
"Unknown": "알 수 없음",
"Untitled": "제목 없음",
"Updated:": "업데이트일:",
"User avatar": "사용자 아바타",
"Updated": "업데이트일",
"Version {{version}}": "버전 {{version}}",
"Vertical Direction": "수직 방향",
"Welcome to your library. You can import your books here and read them anytime.": "내 서재에 오신 것을 환영합니다. 여기에서 책을 가져와 언제든지 읽을 수 있습니다.",
@@ -121,26 +108,21 @@
"Your Library": "내 서재",
"TTS not supported for PDF": "PDF에서 TTS가 지원되지 않음",
"Override Book Font": "책 글꼴 덮어쓰기",
"Vertical Margins (px)": "수직 여백 (px)",
"Horizontal Margins (%)": "수평 여백 (%)",
"Apply to All Books": "모든 책에 적용",
"Apply to This Book": "이 책에 적용",
"Unable to fetch the translation. Try again later.": "번역을 가져올 수 없습니다. 나중에 다시 시도하세요.",
"Update Now!": "지금 업데이트!",
"Update": "업데이트",
"Check Update": "업데이트 확인",
"Already the latest version": "이미 최신 버전",
"Book Details": "책 세부 정보",
"From Local File": "로컬 파일에서",
"TOC": "목차",
"Table of Contents": "목차",
"Book uploaded: {{title}}": "책 업로드됨: {{title}}",
"Failed to upload book: {{title}}": "책 업로드 실패: {{title}}",
"Book downloaded: {{title}}": "책 다운로드됨: {{title}}",
"Failed to download book: {{title}}": "책 다운로드 실패: {{title}}",
"Upload Book": "책 업로드",
"Auto Upload Books to Cloud": "책 자동으로 클라우드에 업로드",
"{{percentage}}% of Cloud Storage Used.": "클라우드 저장소 사용량 {{percentage}}%.",
"Storage": "저장소",
"Book deleted: {{title}}": "책 삭제됨: {{title}}",
"Failed to delete book: {{title}}": "책 삭제 실패: {{title}}",
"Check Updates on Start": "시작 시 업데이트 확인",
@@ -172,7 +154,7 @@
"Create a Password": "비밀번호 만들기",
"Sign up": "회원가입",
"Signing up...": "회원가입 중...",
"Dont have an account? Sign up": "계정이 없습니까? 회원가입",
"Don't have an account? Sign up": "계정이 없습니까? 회원가입",
"Check your email for the confirmation link": "확인 링크를 위해 이메일을 확인하세요",
"Signing in ...": "로그인 중 ...",
"Send a magic link email": "마법의 링크 이메일 보내기",
@@ -191,41 +173,15 @@
"Token": "토큰",
"Your OTP token": "당신의 OTP 토큰",
"Verify token": "토큰 확인",
"Sign in with Google": "Google로 로그인",
"Sign in with Apple": "Apple로 로그인",
"Sign in with GitHub": "GitHub로 로그인",
"Account": "계정",
"Cloud Storage": "클라우드 스토리지",
"Failed to delete user. Please try again later.": "사용자 삭제에 실패했습니다. 나중에 다시 시도해 주세요.",
"Unlimited Offline/Online Reading": "무제한 오프라인/온라인 읽기",
"Unlimited Cloud Sync Devices": "무제한 클라우드 동기화 기기",
"Essential Text-to-Speech Voices": "필수 텍스트 음성 변환 목소리",
"DeepL Free Access": "DeepL 무료 접근",
"Community Support": "커뮤니티 지원",
"500 MB Cloud Sync Space": "500 MB 클라우드 동기화 공간",
"Includes All Free Tier Benefits": "무료 등급의 모든 혜택 포함",
"AI Summaries": "AI 요약",
"AI Translations": "AI 번역",
"Priority Support": "우선 지원",
"DeepL Pro Access": "DeepL 프로 접근",
"Expanded Text-to-Speech Voices": "확장된 텍스트 음성 변환 목소리",
"2000 MB Cloud Sync Space": "2000 MB 클라우드 동기화 공간",
"Includes All Plus Tier Benefits": "플러스 등급의 모든 혜택 포함",
"Unlimited AI Summaries": "무제한 AI 요약",
"Unlimited AI Translations": "무제한 AI 번역",
"Unlimited DeepL Pro Access": "무제한 DeepL 프로 접근",
"Advanced AI Tools": "고급 AI 도구",
"Early Feature Access": "신기능 조기 접근",
"10 GB Cloud Sync Space": "10 GB 클라우드 동기화 공간",
"Loading profile...": "프로필 로딩 중...",
"Features": "기능",
"Delete Account": "계정 삭제",
"Delete Your Account?": "계정을 삭제하시겠습니까?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "이 작업은 취소할 수 없습니다. 클라우드에 있는 모든 데이터가 영구적으로 삭제됩니다.",
"Delete Permanently": "영구 삭제",
"Free Tier": "무료 등급",
"Plus Tier": "플러스 등급",
"Pro Tier": "프로 등급",
"RTL Direction": "RTL 방향",
"Maximum Column Height": "최대 열 높이",
"Maximum Column Width": "최대 열 너비",
@@ -234,7 +190,7 @@
"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": "텍스트 색상",
@@ -259,11 +215,809 @@
"Copied to clipboard": "클립보드에 복사",
"Export Annotations": "주석 내보내기",
"Auto Import on File Open": "파일 열 때 자동 가져오기",
"LXGW WenKai GB Screen": "LXGW WenKai",
"Swap Click-to-Flip Area": "클릭-뒤집기 영역 교환",
"No chapters detected.": "장 발견되지 않음.",
"Failed to parse the EPUB file.": "EPUB 파일 구문 분석 실패.",
"This book format is not supported.": "이 책 형식은 지원되지 않습니다.",
"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": "이 책 형식은 지원되지 않습니다",
"Unable to fetch the translation. Please log in first and try again.": "번역을 가져올 수 없습니다. 먼저 로그인하고 다시 시도하세요.",
"Group": "그룹"
"Group": "그룹",
"Always on Top": "항상 위에",
"No Timeout": "타임아웃 없음",
"{{value}} minute": "{{value}} 분",
"{{value}} minutes": "{{value}} 분",
"{{value}} hour": "{{value}} 시간",
"{{value}} hours": "{{value}} 시간",
"CJK Font": "CJK 글꼴",
"Clear Search": "검색 지우기",
"Header & Footer": "헤더 및 푸터",
"Apply also in Scrolled Mode": "스크롤 모드에서도 적용",
"A new version of Readest is available!": "Readest의 새 버전이 있습니다!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}}가 사용 가능 (설치된 버전 {{currentVersion}}).",
"Download and install now?": "지금 다운로드하고 설치하시겠습니까?",
"Downloading {{downloaded}} of {{contentLength}}": "다운로드 중 {{downloaded}} / {{contentLength}}",
"Download finished": "다운로드 완료",
"DOWNLOAD & INSTALL": "다운로드 및 설치",
"Changelog": "변경 로그",
"Software Update": "소프트웨어 업데이트",
"Title": "제목",
"Date Read": "읽은 날짜",
"Date Added": "추가된 날짜",
"Format": "형식",
"Ascending": "오름차순",
"Descending": "내림차순",
"Sort by...": "정렬 기준...",
"Added": "추가됨",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description": "설명",
"No description available": "설명 없음",
"List": "목록",
"Grid": "격자",
"(from 'As You Like It', Act II)": "(당신이 좋아하는 대로, 2막)",
"Link Color": "링크 색상",
"Volume Keys for Page Flip": "페이지 넘김을 위한 볼륨 키",
"Screen": "화면",
"Orientation": "방향",
"Portrait": "세로",
"Landscape": "가로",
"Open Last Book on Start": "시작 시 마지막 책 열기",
"Checking for updates...": "업데이트 확인 중...",
"Error checking for updates": "업데이트 확인 중 오류 발생",
"Details": "세부정보",
"File Size": "파일 크기",
"Auto Detect": "자동 감지",
"Next Section": "다음 섹션",
"Previous Section": "이전 섹션",
"Next Page": "다음 페이지",
"Previous Page": "이전 페이지",
"Are you sure to delete {{count}} selected book(s)?_other": "선택한 {{count}}권의 책을 삭제하시겠습니까?",
"Are you sure to delete the selected book?": "선택한 책을 삭제하시겠습니까?",
"Deselect": "해제",
"Select All": "전체선택",
"No translation available.": "번역이 없습니다.",
"Translated by {{provider}}.": "{{provider}}에 의해 번역됨.",
"DeepL": "DeepL",
"Google Translate": "구글 번역",
"Azure Translator": "Azure 번역기",
"Invert Image In Dark Mode": "어두운 곳에서 이미지 반전",
"Help improve Readest": "Readest 개선에 도움을 주세요",
"Sharing anonymized statistics": "익명화된 통계 공유",
"Interface Language": "인터페이스 언어",
"Translation": "번역",
"Enable Translation": "번역 활성화",
"Translation Service": "번역 서비스",
"Translate To": "번역 대상 언어",
"Disable Translation": "번역 비활성화",
"Scroll": "스크롤",
"Overlap Pixels": "겹치는 픽셀",
"System Language": "시스템 언어",
"Security": "보안",
"Allow JavaScript": "JavaScript 허용",
"Enable only if you trust the file.": "파일을 신뢰하는 경우에만 활성화하세요.",
"Sort TOC by Page": "목차를 페이지별로 정렬",
"Search in {{count}} Book(s)..._other": "{{count}}권의 책에서 검색...",
"No notes match your search": "일치하는 노트가 없습니다",
"Search notes and excerpts...": "노트 검색...",
"Sign in to Sync": "동기화를 위해 로그인하세요",
"Synced at {{time}}": "{{time}}에 동기화됨",
"Never synced": "동기화된 적 없음",
"Show Remaining Time": "남은 시간 표시",
"{{time}} min left in chapter": "{{time}}분 남음",
"Override Book Color": "책 색상 덮어쓰기",
"Login Required": "로그인 필요",
"Quota Exceeded": "한도 초과",
"{{percentage}}% of Daily Translation Characters Used.": "일일 번역 문자 사용량 {{percentage}}%.",
"Translation Characters": "번역 문자",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}}개의 음성",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "문제가 발생했습니다. 걱정하지 마세요, 저희 팀이 이미 알림을 받았으며 해결 작업을 진행 중입니다.",
"Error Details:": "오류 세부사항:",
"Try Again": "다시 시도",
"Need help?": "도움이 필요하신가요?",
"Contact Support": "지원팀에 문의",
"Code Highlighting": "코드 하이라이팅",
"Enable Highlighting": "하이라이팅 활성화",
"Code Language": "코드 언어",
"Top Margin (px)": "위쪽 여백 (px)",
"Bottom Margin (px)": "아래쪽 여백 (px)",
"Right Margin (px)": "오른쪽 여백 (px)",
"Left Margin (px)": "왼쪽 여백 (px)",
"Column Gap (%)": "열 간격 (%)",
"Always Show Status Bar": "상태 표시줄 항상 표시",
"Custom Content CSS": "콘텐츠 CSS",
"Enter CSS for book content styling...": "도서 콘텐츠 스타일을 위한 CSS 입력...",
"Custom Reader UI CSS": "리더 UI CSS",
"Enter CSS for reader interface styling...": "리더 인터페이스 스타일용 CSS 입력...",
"Crop": "자르기",
"Book Covers": "책 표지",
"Fit": "맞춤",
"Reset {{settings}}": "{{settings}} 재설정",
"Reset Settings": "설정 재설정",
"{{count}} pages left in chapter_other": "남은 페이지 {{count}}장",
"Show Remaining Pages": "남은 페이지 보기",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "구독 관리",
"Coming Soon": "곧 출시 예정",
"Upgrade to {{plan}}": "{{plan}}로 업그레이드",
"Upgrade to Plus or Pro": "Plus 또는 Pro로 업그레이드",
"Current Plan": "현재 요금제",
"Plan Limits": "요금제 한도",
"Processing your payment...": "결제를 처리 중입니다...",
"Please wait while we confirm your subscription.": "구독을 확인하는 중입니다. 잠시만 기다려주세요.",
"Payment Processing": "결제 처리 중",
"Your payment is being processed. This usually takes a few moments.": "결제가 처리되고 있습니다. 잠시만 기다려주세요.",
"Payment Failed": "결제 실패",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "구독을 처리할 수 없습니다. 다시 시도하거나 문제가 계속되면 지원팀에 문의해주세요.",
"Back to Profile": "프로필로 돌아가기",
"Subscription Successful!": "구독이 완료되었습니다!",
"Thank you for your subscription! Your payment has been processed successfully.": "구독해주셔서 감사합니다! 결제가 성공적으로 처리되었습니다.",
"Email:": "이메일:",
"Plan:": "요금제:",
"Amount:": "금액:",
"Go to Library": "라이브러리로 이동",
"Need help? Contact our support team at support@readest.com": "도움이 필요하시면 support@readest.com으로 문의해주세요.",
"Free Plan": "무료 요금제",
"month": "월",
"AI Translations (per day)": "AI 번역 (일 기준)",
"Plus Plan": "Plus 요금제",
"Includes All Free Plan Benefits": "무료 요금제의 모든 혜택 포함",
"Pro Plan": "Pro 요금제",
"More AI Translations": "더 많은 AI 번역",
"Complete Your Subscription": "구독 완료",
"{{percentage}}% of Cloud Sync Space Used.": "{{percentage}}%의 클라우드 동기화 공간 사용됨.",
"Cloud Sync Storage": "클라우드 저장 공간",
"Disable": "비활성화",
"Enable": "활성화",
"Upgrade to Readest Premium": "Readest Premium으로 업그레이드",
"Show Source Text": "원본 텍스트 표시",
"Cross-Platform Sync": "크로스 플랫폼 동기화",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "라이브러리와 진행 상황을 모든 기기에서 동기화합니다.",
"Customizable Reading": "맞춤형 읽기",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "폰트, 레이아웃, 테마를 자유롭게 조정하세요.",
"AI Read Aloud": "AI 음성 읽기",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "자연스러운 AI 음성으로 책을 들어보세요.",
"AI Translations": "AI 번역",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Google, Azure, DeepL로 즉시 번역합니다.",
"Connect with fellow readers and get help fast in our friendly community channels.": "커뮤니티에서 도움과 소통을 즐기세요.",
"Unlimited AI Read Aloud Hours": "무제한 AI 음성 읽기",
"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 이용",
"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": "모든 플러스 플랜 혜택 포함",
"Early Feature Access": "신기능 우선 액세스",
"Be the first to explore new features, updates, and innovations before anyone else.": "새로운 기능, 업데이트, 혁신을 누구보다 먼저 체험하세요.",
"Advanced AI Tools": "고급 AI 도구",
"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만 자를 번역하세요.",
"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}}",
"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": "남은 페이지 {{number}}장",
"Device": "장치",
"E-Ink Mode": "E-Ink 모드",
"Highlight Colors": "하이라이트 색상",
"Auto Screen Brightness": "자동 화면 밝기",
"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": "탭하여 바닥글 전환",
"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": "챕터 선택",
"{{number}} WPM": "{{number}} WPM",
"Context": "문맥",
"Ready": "준비됨",
"Chapter Progress": "챕터 진행 상황",
"words": "단어",
"{{time}} left": "{{time}} 남음",
"Reading progress": "독서 진행 상황",
"Click to seek": "클릭하여 탐색",
"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+오른쪽 화살표)",
"Pause:": "일시정지:",
"Decrease speed": "속도 줄이기",
"Slower (Left/Down)": "느리게 (왼쪽/아래 화살표)",
"Current speed": "현재 속도",
"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 위치로 돌아가기"
}
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
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
File diff suppressed because it is too large Load Diff
@@ -5,11 +5,9 @@
"Animation": "Animasyon",
"Annotate": "Not Ekle",
"Apply": "Uygula",
"Are you sure to delete the selected books?": "Seçili kitapları silmek istediğinizden emin misiniz?",
"Auto Mode": "Otomatik Mod",
"Behavior": "Davranış",
"Book": "Kitap",
"Book Cover": "Kitap Kapağı",
"Bookmark": "Yer İmi",
"Cancel": "İptal",
"Chapter": "Bölüm",
@@ -19,7 +17,6 @@
"Confirm Deletion": "Silmeyi Onayla",
"Copied to notebook": "Not defterine kopyalandı",
"Copy": "Kopyala",
"Custom CSS": "Özel CSS",
"Dark Mode": "Karanlık Mod",
"Default": "Varsayılan",
"Default Font": "Varsayılan Yazı Tipi",
@@ -27,10 +24,8 @@
"Delete": "Sil",
"Delete Highlight": "Vurguyu Sil",
"Dictionary": "Sözlük",
"Disable Click-to-Flip": "Tıkla-Çevir'i Devre Dışı Bırak",
"Download Readest": "Readest'i İndir",
"Edit": "Düzenle",
"Enter your custom CSS here...": "Özel CSS'nizi buraya girin...",
"Excerpts": "Alıntılar",
"Failed to import book(s): {{filenames}}": "Kitap(lar) içe aktarılamadı: {{filenames}}",
"Fast": "Hızlı",
@@ -43,17 +38,13 @@
"Global Settings": "Genel Ayarlar",
"Go Back": "Geri Git",
"Go Forward": "İleri Git",
"Go Left": "Sola Git",
"Go Right": "Sağa Git",
"Grass": "Çimen",
"Gray": "Gri",
"Gruvbox": "Gruvbox",
"Highlight": "Vurgula",
"Horizontal Direction": "Yatay Yön",
"Hyphenation": "Heceleme",
"Identifier:": "Tanımlayıcı:",
"Import Books": "Kitapları İçe Aktar",
"Language:": "Dil:",
"Layout": "Düzen",
"Light Mode": "Aydınlık Mod",
"Loading...": "Yükleniyor...",
@@ -64,7 +55,6 @@
"Match Whole Words": "Tam Kelimeleri Eşleştir",
"Maximum Number of Columns": "Maksimum Sütun Sayısı",
"Minimum Font Size": "Minimum Yazı Boyutu",
"Misc": "Diğer",
"Monospace Font": "Eş Aralıklı Yazı Tipi",
"More Info": "Daha Fazla Bilgi",
"Nord": "Nord",
@@ -76,8 +66,8 @@
"Paging Animation": "Sayfa Çevirme Animasyonu",
"Paragraph": "Paragraf",
"Parallel Read": "Paralel Okuma",
"Published:": "Yayınlanma:",
"Publisher:": "Yayıncı:",
"Published": "Yayınlanma",
"Publisher": "Yayıncı",
"Reading Progress Synced": "Okuma ilerlemesi senkronize edildi",
"Reload Page": "Sayfayı Yenile",
"Reveal in File Explorer": "Dosya Gezgininde Göster",
@@ -91,7 +81,6 @@
"Search...": "Ara...",
"Select Book": "Kitap Seç",
"Select Books": "Kitapları seç",
"Select Multiple Books": "Birden fazla kitap seç",
"Sepia": "Sepya",
"Serif Font": "Serif Yazı Tipi",
"Show Book Details": "Kitap Detaylarını Göster",
@@ -102,17 +91,15 @@
"Slow": "Yavaş",
"Solarized": "Solarized",
"Speak": "Konuş",
"Subjects:": "Konular:",
"Subjects": "Konular",
"System Fonts": "Sistem Yazı Tipleri",
"TTS not supported in this device": "Bu cihazda TTS desteklenmiyor",
"Theme Color": "Tema Rengi",
"Theme Mode": "Tema Modu",
"Translate": "Çevir",
"Translated Text": "Çevrilen Metin",
"Unknown": "Bilinmiyor",
"Untitled": "Başlıksız",
"Updated:": "Güncellendi:",
"User avatar": "Kullanıcı avatarı",
"Updated": "Güncellendi",
"Version {{version}}": "Sürüm {{version}}",
"Vertical Direction": "Dikey Yön",
"Welcome to your library. You can import your books here and read them anytime.": "Kütüphanenize hoş geldiniz. Buradan kitaplarınızı içe aktarabilir ve istediğiniz zaman okuyabilirsiniz.",
@@ -121,26 +108,21 @@
"Your Library": "Kütüphaneniz",
"TTS not supported for PDF": "PDF için TTS desteklenmiyor",
"Override Book Font": "Kitap Yazı Tipini Geçersiz Kıl",
"Vertical Margins (px)": "Dikey Kenar Boşlukları (px)",
"Horizontal Margins (%)": "Yatay Kenar Boşlukları (%)",
"Apply to All Books": "Tüm kitaplara uygula",
"Apply to This Book": "Bu kitaba uygula",
"Unable to fetch the translation. Try again later.": "Çeviri alınamıyor. Daha sonra tekrar deneyin.",
"Update Now!": "Şimdi Güncelle!",
"Update": "Güncelle",
"Check Update": "Güncellemeyi kontrol et",
"Already the latest version": "Zaten en son sürüm",
"Book Details": "Kitap Detayları",
"From Local File": "Yerel dosyadan",
"TOC": "İçindekiler",
"Table of Contents": "İçindekiler",
"Book uploaded: {{title}}": "Kitap yüklendi: {{title}}",
"Failed to upload book: {{title}}": "Kitap yüklenemedi: {{title}}",
"Book downloaded: {{title}}": "Kitap indirildi: {{title}}",
"Failed to download book: {{title}}": "Kitap indirilemedi: {{title}}",
"Upload Book": "Kitap Yükle",
"Auto Upload Books to Cloud": "Kitapları Otomatik Olarak Buluta Yükle",
"{{percentage}}% of Cloud Storage Used.": "Bulut Depolamanın %{{percentage}}'si kullanıldı.",
"Storage": "Depolama",
"Book deleted: {{title}}": "Kitap silindi: {{title}}",
"Failed to delete book: {{title}}": "Kitap silinemedi: {{title}}",
"Check Updates on Start": "Başlangıçta Güncellemeleri Kontrol Et",
@@ -172,7 +154,7 @@
"Create a Password": "Şifre oluştur",
"Sign up": "Kaydol",
"Signing up...": "Kaydolunuyor...",
"Dont have an account? Sign up": "Hesabınız yok mu? Kaydolun",
"Don't have an account? Sign up": "Hesabınız yok mu? Kaydolun",
"Check your email for the confirmation link": "Onay bağlantısı için e-posta adresinizi kontrol edin",
"Signing in ...": "Giriş yapılıyor...",
"Send a magic link email": "Sihirli bağlantı e-postası gönder",
@@ -191,41 +173,15 @@
"Token": "Token",
"Your OTP token": "OTP token'ınız",
"Verify token": "Token'ı doğrula",
"Sign in with Google": "Google ile giriş yap",
"Sign in with Apple": "Apple ile giriş yap",
"Sign in with GitHub": "GitHub ile giriş yap",
"Account": "Hesap",
"Cloud Storage": "Bulut Depolama",
"Failed to delete user. Please try again later.": "Kullanıcı silinemedi. Lütfen daha sonra tekrar deneyin.",
"Unlimited Offline/Online Reading": "Sınırsız Çevrimdışı/Çevrimiçi Okuma",
"Unlimited Cloud Sync Devices": "Sınırsız Bulut Senkronizasyon Cihazları",
"Essential Text-to-Speech Voices": "Temel Metinden Sese Dönüştürme Sesleri",
"DeepL Free Access": "DeepL Ücretsiz Erişim",
"Community Support": "Topluluk Desteği",
"500 MB Cloud Sync Space": "500 MB Bulut Senkronizasyon Alanı",
"Includes All Free Tier Benefits": "Tüm Ücretsiz Paket Avantajlarını İçerir",
"AI Summaries": "Yapay Zeka Özetleri",
"AI Translations": "Yapay Zeka Çevirileri",
"Priority Support": "Öncelikli Destek",
"DeepL Pro Access": "DeepL Pro Erişimi",
"Expanded Text-to-Speech Voices": "Genişletilmiş Metinden Sese Dönüştürme Sesleri",
"2000 MB Cloud Sync Space": "2000 MB Bulut Senkronizasyon Alanı",
"Includes All Plus Tier Benefits": "Tüm Plus Paket Avantajlarını İçerir",
"Unlimited AI Summaries": "Sınırsız Yapay Zeka Özetleri",
"Unlimited AI Translations": "Sınırsız Yapay Zeka Çevirileri",
"Unlimited DeepL Pro Access": "Sınırsız DeepL Pro Erişimi",
"Advanced AI Tools": "Gelişmiş Yapay Zeka Araçları",
"Early Feature Access": "Erken Özellik Erişimi",
"10 GB Cloud Sync Space": "10 GB Bulut Senkronizasyon Alanı",
"Loading profile...": "Profil yükleniyor...",
"Features": "Özellikler",
"Delete Account": "Hesabı Sil",
"Delete Your Account?": "Hesabınızı Silmek İstiyor musunuz?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "Bu işlem geri alınamaz. Buluttaki tüm verileriniz kalıcı olarak silinecektir.",
"Delete Permanently": "Kalıcı Olarak Sil",
"Free Tier": "Ücretsiz Paket",
"Plus Tier": "Plus Paket",
"Pro Tier": "Pro Paket",
"RTL Direction": "RTL Yönü",
"Maximum Column Height": "Maksimum Sütun Yüksekliği",
"Maximum Column Width": "Maksimum Sütun Genişliği",
@@ -234,7 +190,7 @@
"No supported files found. Supported formats: {{formats}}": "Desteklenen dosya bulunamadı. Desteklenen formatlar: {{formats}}",
"Drop to Import Books": "Kitapları İçe Aktarmak İçin Bırak",
"Custom": "Özel",
"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": "Tüm dünya bir sahnedir,\nVe tüm erkekler ve kadınlar sadece oyunculardır;\nOnların çıkışları ve girişleri vardır,\nVe bir adam zamanında birçok rol oynar,\nOnun eylemleri yedi yaşındadır.\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": "Tüm dünya bir sahnedir,\nVe tüm erkekler ve kadınlar sadece oyunculardır;\nOnların çıkışları ve girişleri vardır,\nVe bir adam zamanında birçok rol oynar,\nOnun eylemleri yedi yaşındadır.\n\n— William Shakespeare",
"Custom Theme": "Özel Tema",
"Theme Name": "Tema Adı",
"Text Color": "Metin Rengi",
@@ -259,11 +215,821 @@
"Copied to clipboard": "Panoya kopyalandı",
"Export Annotations": "Notları Dışa Aktar",
"Auto Import on File Open": "Dosya Açıldığında Otomatik İçe Aktar",
"LXGW WenKai GB Screen": "LXGW WenKai",
"Swap Click-to-Flip Area": "Tıkla-Çevir Alanını Değiştir",
"No chapters detected.": "Bölüm bulunamadı.",
"Failed to parse the EPUB file.": "EPUB dosyası ayrıştırılamadı.",
"This book format is not supported.": "Bu kitap formatı desteklenmiyor.",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected": "Bölüm bulunamadı",
"Failed to parse the EPUB file": "EPUB dosyası ayrıştırılamadı",
"This book format is not supported": "Bu kitap formatı desteklenmiyor",
"Unable to fetch the translation. Please log in first and try again.": "Çeviri alınamıyor. Lütfen önce giriş yapın ve tekrar deneyin.",
"Group": "Grup"
"Group": "Grup",
"Always on Top": "Her Zaman Üstte",
"No Timeout": "Zaman Aşımı Yok",
"{{value}} minute": "{{value}} dakika",
"{{value}} minutes": "{{value}} dakika",
"{{value}} hour": "{{value}} saat",
"{{value}} hours": "{{value}} saat",
"CJK Font": "CJK Yazı Tipi",
"Clear Search": "Aramayı Temizle",
"Header & Footer": "Başlık ve Altbilgi",
"Apply also in Scrolled Mode": "Kaydırılmış Modda da Uygula",
"A new version of Readest is available!": "Yeni bir Readest sürümü mevcut!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} mevcut (yüklü sürüm {{currentVersion}}).",
"Download and install now?": "Şimdi indirip yükleyelim mi?",
"Downloading {{downloaded}} of {{contentLength}}": "İndiriliyor {{downloaded}}/{{contentLength}}",
"Download finished": "İndirme tamamlandı",
"DOWNLOAD & INSTALL": "İNDİR & YÜKLE",
"Changelog": "Değişiklik Günlüğü",
"Software Update": "Yazılım Güncellemesi",
"Title": "Başlık",
"Date Read": "Okunma Tarihi",
"Date Added": "Eklenme Tarihi",
"Format": "Biçim",
"Ascending": "Artan",
"Descending": "Azalan",
"Sort by...": "Şuna göre sırala...",
"Added": "Eklenme",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description": "Tanım",
"No description available": "Tanım mevcut değil",
"List": "Liste",
"Grid": "Izgara",
"(from 'As You Like It', Act II)": "(As You Like It, 2. Perde)",
"Link Color": "Bağlantı Rengi",
"Volume Keys for Page Flip": "Sayfa Çevirme için Ses Seviyesi Tuşları",
"Screen": "Ekran",
"Orientation": "Yönlendirme",
"Portrait": "Portre",
"Landscape": "Yatay",
"Open Last Book on Start": "Açılışta Son Kitabı Aç",
"Checking for updates...": "Yenilikler kontrol ediliyor...",
"Error checking for updates": "Güncellemeleri kontrol ederken hata oluştu",
"Details": "Detaylar",
"File Size": "Dosya Boyutu",
"Auto Detect": "Algıla",
"Next Section": "Sonraki Bölüm",
"Previous Section": "Önceki Bölüm",
"Next Page": "Sonraki Sayfa",
"Previous Page": "Önceki Sayfa",
"Are you sure to delete {{count}} selected book(s)?_one": "{{count}} seçili kitabı silmek istediğinize emin misiniz?",
"Are you sure to delete {{count}} selected book(s)?_other": "{{count}} seçili kitabı silmek istediğinize emin misiniz?",
"Are you sure to delete the selected book?": "Seçili kitabı silmek istediğinize emin misiniz?",
"Deselect": "Kaldır",
"Select All": "Hepsi",
"No translation available.": "Çeviri mevcut değil.",
"Translated by {{provider}}.": "{{provider}} tarafından çevrildi.",
"DeepL": "DeepL",
"Google Translate": "Google Çeviri",
"Azure Translator": "Azure Çevirmen",
"Invert Image In Dark Mode": "Karartılmış Görüntüyü Ters Çevir",
"Help improve Readest": "Readesti geliştirin",
"Sharing anonymized statistics": "Anonim verileri paylaş",
"Interface Language": "Arayüz Dili",
"Translation": "Çeviri",
"Enable Translation": "Çeviriyi Etkinleştir",
"Translation Service": "Çeviri Hizmeti",
"Translate To": "Şuna Çevir",
"Disable Translation": "Çeviriyi Devre Dışı Bırak",
"Scroll": "Kaydır",
"Overlap Pixels": "Örtüşen Pikseller",
"System Language": "System Dili",
"Security": "Security",
"Allow JavaScript": "JavaScript'e İzin Ver",
"Enable only if you trust the file.": "Yalnızca dosyaya güveniyorsanız etkinleştirin.",
"Sort TOC by Page": "İçindekileri Sayfaya Göre Sırala",
"Search in {{count}} Book(s)..._one": "{{count}} kitapta ara...",
"Search in {{count}} Book(s)..._other": "{{count}} kitapta ara...",
"No notes match your search": "Eşleşen not bulunamadı",
"Search notes and excerpts...": "Notlarda ara...",
"Sign in to Sync": "Giriş yap",
"Synced at {{time}}": "{{time}}'de eşzlendi",
"Never synced": "Hiç eşzlenmedi",
"Show Remaining Time": "Kalan Süreyi Göster",
"{{time}} min left in chapter": "{{time}} dakika bölümde kaldı",
"Override Book Color": "Kitap Rengini Geçersiz Kıl",
"Login Required": "Giriş gerekli",
"Quota Exceeded": "Kota aşıldı",
"{{percentage}}% of Daily Translation Characters Used.": "Çeviri için günlük karakterlerin %{{percentage}}'si kullanıldı.",
"Translation Characters": "Çeviri Karakterleri",
"{{engine}}: {{count}} voices_one": "{{engine}}: {{count}} ses",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}} sesler",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "Bir şeyler yanlış gitti. Endişelenmeyin, ekibimiz bilgilendirildi ve bir çözüm üzerinde çalışıyoruz.",
"Error Details:": "Error Detayları:",
"Try Again": "Tekrar Dene",
"Need help?": "Yardıma mı ihtiyacınız var?",
"Contact Support": "Destekle İletişime Geç",
"Code Highlighting": "Code Vurgulama",
"Enable Highlighting": "Vurgulamayı Etkinleştir",
"Code Language": "Code Dili",
"Top Margin (px)": "Üst Kenar Boşluğu (px)",
"Bottom Margin (px)": "Alt Kenar Boşluğu (px)",
"Right Margin (px)": "Sağ Kenar Boşluğu (px)",
"Left Margin (px)": "Sol Kenar Boşluğu (px)",
"Column Gap (%)": "Sütun Aralığı (%)",
"Always Show Status Bar": "Durum Çubuğunu Her Zaman Göster",
"Custom Content CSS": "Özel İçerik CSS'si",
"Enter CSS for book content styling...": "Kitap içeriği stili için CSS girin...",
"Custom Reader UI CSS": "Özel Okuyucu Arayüzü CSS'si",
"Enter CSS for reader interface styling...": "Okuyucu arayüzü stili için CSS girin...",
"Crop": "Kes",
"Book Covers": "Kitap Kapağı",
"Fit": "Uygun",
"Reset {{settings}}": "{{settings}}'i Sıfırla",
"Reset Settings": "Ayarları Sıfırla",
"{{count}} pages left in chapter_one": "Bu bölümde {{count}} sayfa kaldı",
"{{count}} pages left in chapter_other": "Bu bölümde {{count}} sayfa kaldı",
"Show Remaining Pages": "Kalan sayfaları göster",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Aboneliği Yönet",
"Coming Soon": "Yakında",
"Upgrade to {{plan}}": "{{plan}} planına yükselt",
"Upgrade to Plus or Pro": "Plus veya Pro'ya yükselt",
"Current Plan": "Mevcut Plan",
"Plan Limits": "Plan Limitleri",
"Processing your payment...": "Ödemeniz işleniyor...",
"Please wait while we confirm your subscription.": "Aboneliğinizi onaylıyoruz, lütfen bekleyin.",
"Payment Processing": "Ödeme İşleniyor",
"Your payment is being processed. This usually takes a few moments.": "Ödemeniz işleniyor. Bu genelde birkaç saniye sürer.",
"Payment Failed": "Ödeme Başarısız",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "Aboneliğinizi işleyemedik. Lütfen tekrar deneyin veya sorun devam ederse destek ile iletişime geçin.",
"Back to Profile": "Profille Dön",
"Subscription Successful!": "Abonelik Başarılı!",
"Thank you for your subscription! Your payment has been processed successfully.": "Aboneliğiniz için teşekkürler! Ödemeniz başarıyla işlendi.",
"Email:": "E-posta:",
"Plan:": "Plan:",
"Amount:": "Tutar:",
"Go to Library": "Kütüphaneye Git",
"Need help? Contact our support team at support@readest.com": "Yardım mı gerekiyor? Destek ekibimizle iletişime geçin: support@readest.com",
"Free Plan": "Ücretsiz Plan",
"month": "ay",
"AI Translations (per day)": "AI Çevirileri (günlük)",
"Plus Plan": "Plus Plan",
"Includes All Free Plan Benefits": "Tüm Ücretsiz Plan Özelliklerini İçerir",
"Pro Plan": "Pro Plan",
"More AI Translations": "Daha Fazla AI Çevirisi",
"Complete Your Subscription": "Aboneliğinizi Tamamlayın",
"{{percentage}}% of Cloud Sync Space Used.": "Bulut Senkronizasyon Alanının %{{percentage}}'si Kullanıldı.",
"Cloud Sync Storage": "Bulut Senkronizasyon Depolama",
"Disable": "Devre Dışı Bırak",
"Enable": "Etkinleştir",
"Upgrade to Readest Premium": "Readest Premiuma Yükselt",
"Show Source Text": "Kaynak Metni Göster",
"Cross-Platform Sync": "Platformlar Arası Senkronizasyon",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "Kütüphanenizi, ilerlemenizi, vurgularınızı ve notlarınızı tüm cihazlarınızda sorunsuzca senkronize edin—bir daha asla yerinizi kaybetmeyin.",
"Customizable Reading": "Özelleştirilebilir Okuma",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "Mükemmel okuma deneyimi için ayarlanabilir yazı tipleri, düzenler, temalar ve gelişmiş görüntü ayarlarıyla her detayı kişiselleştirin.",
"AI Read Aloud": "AI Sesli Okuma",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "Kitaplarınızı hayata geçiren doğal sesli AI sesleriyle eller serbest okuma keyfini çıkarın.",
"AI Translations": "AI Çeviriler",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Google, Azure veya DeepL'in gücüyle herhangi bir metni anında çevirin—her dildeki içeriği anlayın.",
"Connect with fellow readers and get help fast in our friendly community channels.": "Diğer okuyucularla bağlantı kurun ve dostane topluluk kanallarımızda hızla yardım alın.",
"Unlimited AI Read Aloud Hours": "Sınırsız AI Sesli Okuma Saatleri",
"Listen without limits—convert as much text as you like into immersive audio.": "Sınırsız dinleyin—istediğiniz kadar metni sürükleyici sese dönüştürün.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Daha fazla günlük kullanım ve gelişmiş seçeneklerle gelişmiş çeviri yeteneklerinin kilidini açın.",
"DeepL Pro Access": "DeepL Pro Erişimi",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Yardıma ihtiyacınız olduğunda daha hızlı yanıtlar ve özel destek keyfini çıkarın.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Günlük çeviri kotasına ulaşıldı. AI çevirileri kullanmaya devam etmek için planınızı yükseltin.",
"Includes All Plus Plan Benefits": "Tüm Plus Plan Avantajları Dahil",
"Early Feature Access": "Erken Özellik Erişimi",
"Be the first to explore new features, updates, and innovations before anyone else.": "Yeni özellikleri, güncellemeleri ve yenilikleri herkesten önce keşfedin.",
"Advanced AI Tools": "Gelişmiş AI Araçları",
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Akıllı okuma, çeviri ve içerik keşfi için güçlü AI araçlarını kullanın.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Mevcut en doğru çeviri motoruyla günlük 100.000 karaktere kadar çeviri yapın.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Mevcut en doğru çeviri motoruyla günlük 500.000 karaktere kadar çeviri yapın.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Tüm okuma koleksiyonunuzu 5 GB'a kadar güvenli bulut depolamayla saklayın ve erişin.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Tüm okuma koleksiyonunuzu 20 GB'a kadar güvenli bulut depolamayla saklayın ve erişin.",
"Deleted cloud backup of the book: {{title}}": "Kitabın bulut yedeği silindi: {{title}}",
"Are you sure to delete the cloud backup of the selected book?": "Seçilen kitabın bulut yedeğini silmek istediğinize emin misiniz?",
"What's New in Readest": "Readest'te Neler Yeni",
"Enter book title": "Kitap başlığını girin",
"Subtitle": "Alt başlık",
"Enter book subtitle": "Kitap alt başlığını girin",
"Enter author name": "Yazar adını girin",
"Series": "Seri",
"Enter series name": "Seri adını girin",
"Series Index": "Seri numarası",
"Enter series index": "Seri numarasını girin",
"Total in Series": "Serideki toplam",
"Enter total books in series": "Serideki toplam kitap sayısını girin",
"Enter publisher": "Yayınevini girin",
"Publication Date": "Yayın tarihi",
"Identifier": "Tanımlayıcı",
"Enter book description": "Kitap açıklamasını girin",
"Change cover image": "Kapak resmini değiştir",
"Replace": "Değiştir",
"Unlock cover": "Kapağın kilidini aç",
"Lock cover": "Kapağı kilitle",
"Auto-Retrieve Metadata": "Meta verileri otomatik al",
"Auto-Retrieve": "Otomatik alma",
"Unlock all fields": "Tüm alanların kilidini aç",
"Unlock All": "Tümünün kilidini aç",
"Lock all fields": "Tüm alanları kilitle",
"Lock All": "Tümünü kilitle",
"Reset": "Sıfırla",
"Edit Metadata": "Meta verileri düzenle",
"Locked": "Kilitli",
"Select Metadata Source": "Meta veri kaynağını seç",
"Keep manual input": "Manuel girişi koru",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Kurgu, Bilim, Tarih",
"Open Book in New Window": "Kitabı Yeni Pencerede Aç",
"Voices for {{lang}}": "{{lang}} için Sesler",
"Yandex Translate": "Yandex Çeviri",
"YYYY or YYYY-MM-DD": "YYYY veya YYYY-MM-DD",
"Restore Purchase": "Satın Almayı Geri Yükle",
"No purchases found to restore.": "Geri yüklemek için satın alma bulunamadı.",
"Failed to restore purchases.": "Satın alımları geri yükleme başarısız oldu.",
"Failed to manage subscription.": "Aboneliği yönetme başarısız oldu.",
"Failed to load subscription plans.": "Abonelik planlarını yükleme başarısız oldu.",
"year": "yıl",
"Failed to create checkout session": "Ödeme oturumu oluşturma başarısız oldu",
"Storage": "Depolama",
"Terms of Service": "Hizmet Şartları",
"Privacy Policy": "Gizlilik Politikası",
"Disable Double Click": "Çift Tıklamayı Devre Dışı Bırak",
"TTS not supported for this document": "TTS bu belge için desteklenmiyor",
"Reset Password": "Şifreyi Sıfırla",
"Show Reading Progress": "Okuma İlerlemesini Göster",
"Reading Progress Style": "Okuma İlerlemesi Stili",
"Page Number": "Sayfa Numarası",
"Percentage": "Yüzde",
"Deleted local copy of the book: {{title}}": "Kitabın yerel kopyası silindi: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Kitabın bulut yedeğini silme başarısız oldu: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Kitabın yerel kopyasını silme başarısız oldu: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Seçilen kitabın yerel kopyasını silmek istediğinize emin misiniz?",
"Remove from Cloud & Device": "Buluttan ve Cihazdan Kaldır",
"Remove from Cloud Only": "Sadece Buluttan Kaldır",
"Remove from Device Only": "Sadece Cihazdan Kaldır",
"Disconnected": "Bağlantı Kesildi",
"KOReader Sync Settings": "KOReader Senkronizasyon Ayarları",
"Sync Strategy": "Senkronizasyon Stratejisi",
"Ask on conflict": "Çatışmada Sor",
"Always use latest": "Her Zaman En Sonunu Kullan",
"Send changes only": "Sadece Değişiklikleri Gönder",
"Receive changes only": "Sadece Değişiklikleri Al",
"Checksum Method": "Kontrol Toplamı Yöntemi",
"File Content (recommended)": "Dosya İçeriği (önerilen)",
"File Name": "Dosya Adı",
"Device Name": "Cihaz Adı",
"Connect to your KOReader Sync server.": "KOReader Senkronizasyon sunucunuza bağlanın.",
"Server URL": "Sunucu URL'si",
"Username": "Kullanıcı Adı",
"Your Username": "Kullanıcı Adınız",
"Password": "Şifre",
"Connect": "Bağlan",
"KOReader Sync": "KOReader Senkronizasyon",
"Sync Conflict": "Senkronizasyon Çatışması",
"Sync reading progress from \"{{deviceName}}\"?": "\"{{deviceName}}\" cihazından okuma ilerlemesini senkronize etmek istiyor musunuz?",
"another device": "başka bir cihaz",
"Local Progress": "Yerel İlerleme",
"Remote Progress": "Uzak İlerleme",
"Page {{page}} of {{total}} ({{percentage}}%)": "Sayfa {{page}} / {{total}} ({{percentage}}%)",
"Current position": "Mevcut konum",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Yaklaşık sayfa {{page}} / {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Yaklaşık {{percentage}}%",
"Failed to connect": "Bağlanma başarısız oldu",
"Sync Server Connected": "Senkronizasyon Sunucusu Bağlandı",
"Sync as {{userDisplayName}}": "Senkronize et {{userDisplayName}} olarak",
"Custom Fonts": "Özel Yazı Tipleri",
"Cancel Delete": "Silmeyi İptal Et",
"Import Font": "Yazı Tipi İçe Aktar",
"Delete Font": "Yazı Tipini Sil",
"Tips": "İpuçları",
"Custom fonts can be selected from the Font Face menu": "Özel yazı tipleri Yazı Tipi menüsünden seçilebilir",
"Manage Custom Fonts": "Özel Yazı Tiplerini Yönet",
"Select Files": "Dosyaları Seç",
"Select Image": "Resim Seç",
"Select Video": "Video Seç",
"Select Audio": "Ses Seç",
"Select Fonts": "Yazı Tiplerini Seç",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Desteklenen yazı tipi formatları: .ttf, .otf, .woff, .woff2",
"Push Progress": "İlerlemeyi Gönder",
"Pull Progress": "İlerlemeyi Al",
"Previous Paragraph": "Önceki Paragraf",
"Previous Sentence": "Önceki Cümle",
"Pause": "Duraklat",
"Play": "Oynat",
"Next Sentence": "Sonraki Cümle",
"Next Paragraph": "Sonraki Paragraf",
"Separate Cover Page": "Ayrı Kapak Sayfası",
"Resize Notebook": "Defteri Yeniden Boyutlandır",
"Resize Sidebar": "Kenar Çubuğunu Yeniden Boyutlandır",
"Get Help from the Readest Community": "Readest Topluluğundan Yardım Alın",
"Remove cover image": "Kapak resmini kaldır",
"Bookshelf": "Kitaplık",
"View Menu": "Menüyü Görüntüle",
"Settings Menu": "Ayarlar Menüsü",
"View account details and quota": "Hesap detaylarını ve kotayı görüntüle",
"Library Header": "Kütüphane Başlığı",
"Book Content": "Kitap İçeriği",
"Footer Bar": "Alt Çubuk",
"Header Bar": "Üst Çubuk",
"View Options": "Görünüm Seçenekleri",
"Book Menu": "Kitap Menüsü",
"Search Options": "Arama Seçenekleri",
"Close": "Kapat",
"Delete Book Options": "Kitap Silme Seçenekleri",
"ON": "AÇIK",
"OFF": "KAPALI",
"Reading Progress": "Okuma İlerlemesi",
"Page Margin": "Sayfa Kenar Boşluğu",
"Remove Bookmark": "Yer İşareti Kaldır",
"Add Bookmark": "Yer İşareti Ekle",
"Books Content": "Kitap İçeriği",
"Jump to Location": "Konuma Atlama",
"Unpin Notebook": "Defteri Sabitlemeyi Kaldır",
"Pin Notebook": "Defteri Sabitle",
"Hide Search Bar": "Arama Çubuğunu Gizle",
"Show Search Bar": "Arama Çubuğunu Göster",
"On {{current}} of {{total}} page": "{{current}} / {{total}} sayfada",
"Section Title": "Bölüm Başlığı",
"Decrease": "Azalt",
"Increase": "Artır",
"Settings Panels": "Ayarlar Panelleri",
"Settings": "Ayarlar",
"Unpin Sidebar": "Kenar Çubuğunu Sabitlemeyi Kaldır",
"Pin Sidebar": "Kenar Çubuğunu Sabitle",
"Toggle Sidebar": "Kenar Çubuğunu Değiştir",
"Toggle Translation": "Çeviriyi Değiştir",
"Translation Disabled": "Çeviri Devre Dışı",
"Minimize": "Küçült",
"Maximize or Restore": "Büyüt veya Geri Yükle",
"Exit Parallel Read": "Paralel Okumadan Çık",
"Enter Parallel Read": "Paralel Okumaya Gir",
"Zoom Level": "Yakınlaştırma Düzeyi",
"Zoom Out": "Yakınlaştırmayı Kaldır",
"Reset Zoom": "Yakınlaştırmayı Sıfırla",
"Zoom In": "Yakınlaştırmayı Artır",
"Zoom Mode": "Yakınlaştırma Modu",
"Single Page": "Tek Sayfa",
"Auto Spread": "Otomatik Yayılma",
"Fit Page": "Sayfaya Sığdır",
"Fit Width": "Genişliğe Sığdır",
"Failed to select directory": "Dizini seçme başarısız oldu",
"The new data directory must be different from the current one.": "Yeni veri dizini mevcut olanla farklı olmalıdır.",
"Migration failed: {{error}}": "Taşıma işlemi başarısız oldu: {{error}}",
"Change Data Location": "Veri Konumunu Değiştir",
"Current Data Location": "Mevcut Veri Konumu",
"Total size: {{size}}": "Toplam boyut: {{size}}",
"Calculating file info...": "Dosya bilgileri hesaplanıyor...",
"New Data Location": "Yeni Veri Konumu",
"Choose Different Folder": "Farklı Klasör Seç",
"Choose New Folder": "Yeni Klasör Seç",
"Migrating data...": "Veri taşınıyor...",
"Copying: {{file}}": "Kopyalanıyor: {{file}}",
"{{current}} of {{total}} files": "{{current}} / {{total}} dosya",
"Migration completed successfully!": "Taşıma işlemi başarıyla tamamlandı!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Verileriniz yeni konuma taşındı. Lütfen işlemi tamamlamak için uygulamayı yeniden başlatın.",
"Migration failed": "Taşıma işlemi başarısız oldu",
"Important Notice": "Önemli Duyuru",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Bu, tüm uygulama verilerinizi yeni konuma taşıyacaktır. Hedefin yeterli boş alana sahip olduğundan emin olun.",
"Restart App": "Uygulamayı Yeniden Başlat",
"Start Migration": "Taşımayı Başlat",
"Advanced Settings": "Gelişmiş Ayarlar",
"File count: {{size}}": "Dosya sayısı: {{size}}",
"Background Read Aloud": "Arka Planda Sesli Okuma",
"Ready to read aloud": "Sesli okumaya hazır",
"Read Aloud": "Sesli Oku",
"Screen Brightness": "Ekran Parlaklığı",
"Background Image": "Arka Plan Görüntüsü",
"Import Image": "Görüntü İçe Aktar",
"Opacity": "Opaklık",
"Size": "Boyut",
"Cover": "Kapak",
"Contain": "İçerir",
"{{number}} pages left in chapter": "Bu bölümde {{number}} sayfa kaldı",
"Device": "Cihaz",
"E-Ink Mode": "E-Ink Modu",
"Highlight Colors": "Vurgu Renkleri",
"Auto Screen Brightness": "Otomatik Ekran Parlaklığı",
"Pagination": "Sayfalama",
"Disable Double Tap": "Çift Dokunmayı Devre Dışı Bırak",
"Tap to Paginate": "Sayfalamak için Dokunun",
"Click to Paginate": "Sayfalamak için Tıklayın",
"Tap Both Sides": "Her İki Tarafa Dokunun",
"Click Both Sides": "Her İki Tarafa Tıklayın",
"Swap Tap Sides": "Dokunma Taraflarını Değiştir",
"Swap Click Sides": "Tıklama Taraflarını Değiştir",
"Source and Translated": "Kaynak ve Çeviri",
"Translated Only": "Yalnızca Çeviri",
"Source Only": "Yalnızca Kaynak",
"TTS Text": "TTS Metni",
"The book file is corrupted": "Kitap dosyası bozulmuş",
"The book file is empty": "Kitap dosyası boş",
"Failed to open the book file": "Kitap dosyası açılamadı",
"On-Demand Purchase": "İhtiyaç Duyulduğunda Satın Alma",
"Full Customization": "Tam Özelleştirme",
"Lifetime Plan": "Ömür Boyu Plan",
"One-Time Payment": "Tek Seferlik Ödeme",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Tüm cihazlarda belirli özelliklere ömür boyu erişim sağlamak için tek seferlik bir ödeme yapın. Belirli özellikleri veya hizmetleri yalnızca ihtiyaç duyduğunuzda satın alın.",
"Expand Cloud Sync Storage": "Bulut Senkronizasyonu Depolama Alanını Genişlet",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Tek seferlik bir satın alma ile bulut depolama alanınızı sonsuza kadar genişletin. Her ek satın alma daha fazla alan ekler.",
"Unlock All Customization Options": "Tüm Özelleştirme Seçeneklerini Aç",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Ek tema, yazı tipi, düzen seçeneklerini ve sesli okuma, çevirmenler, bulut depolama hizmetlerini açın.",
"Purchase Successful!": "Satın Alma Başarılı!",
"lifetime": "ömür boyu",
"Thank you for your purchase! Your payment has been processed successfully.": "Satın alma işleminiz için teşekkürler! Ödemeniz başarıyla işlendi.",
"Order ID:": "Sipariş Kimliği:",
"TTS Highlighting": "TTS Vurgulama",
"Style": "Stil",
"Underline": "Altı Çizili",
"Strikethrough": "Üstü Çizili",
"Squiggly": "Dalgalı Çizgi",
"Outline": "Kontur",
"Save Current Color": "Mevcut Rengi Kaydet",
"Quick Colors": "Hızlı Renkler",
"Highlighter": "Vurgulayıcı",
"Save Book Cover": "Kitap Kapağını Kaydet",
"Auto-save last book cover": "Son kitap kapağını otomatik olarak kaydet",
"Back": "Geri",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Onay e-postası gönderildi! Değişikliği onaylamak için eski ve yeni e-posta adreslerinizi kontrol edin.",
"Failed to update email": "E-posta güncellenemedi",
"New Email": "Yeni e-posta",
"Your new email": "Yeni e-posta adresiniz",
"Updating email ...": "E-posta güncelleniyor ...",
"Update email": "E-postayı güncelle",
"Current email": "Mevcut e-posta",
"Update Email": "E-postayı güncelle",
"All": "Tümü",
"Unable to open book": "Kitap açılamıyor",
"Punctuation": "Noktalama İşaretleri",
"Replace Quotation Marks": "Tırnak İşaretlerini Değiştir",
"Enabled only in vertical layout.": "Yalnızca dikey düzenle etkinleştirildi.",
"No Conversion": "Dönüştürme yok",
"Simplified to Traditional": "Basitleştirilmiş → Geleneksel",
"Traditional to Simplified": "Geleneksel → Basitleştirilmiş",
"Simplified to Traditional (Taiwan)": "Basitleştirilmiş → Geleneksel (Tayvan)",
"Simplified to Traditional (Hong Kong)": "Basitleştirilmiş → Geleneksel (Hong Kong)",
"Simplified to Traditional (Taiwan), with phrases": "Basitleştirilmiş → Geleneksel (Tayvan • ifadeler)",
"Traditional (Taiwan) to Simplified": "Geleneksel (Tayvan) → Basitleştirilmiş",
"Traditional (Hong Kong) to Simplified": "Geleneksel (Hong Kong) → Basitleştirilmiş",
"Traditional (Taiwan) to Simplified, with phrases": "Geleneksel (Tayvan • ifadeler) → Basitleştirilmiş",
"Convert Simplified and Traditional Chinese": "Basitleştirilmiş/Geleneksel Çince Dönüştür",
"Convert Mode": "Dönüştürme Modu",
"Failed to auto-save book cover for lock screen: {{error}}": "Kitap kapağı kilit ekranı için otomatik kaydedilemedi: {{error}}",
"Download from Cloud": "Buluttan İndir",
"Upload to Cloud": "Buluta Yükle",
"Clear Custom Fonts": "Özel Yazı Tiplerini Temizle",
"Columns": "Sütunlar",
"OPDS Catalogs": "OPDS Katalogları",
"Adding LAN addresses is not supported in the web app version.": "Web uygulaması sürümünde LAN adresi ekleme desteklenmiyor.",
"Invalid OPDS catalog. Please check the URL.": "Geçersiz OPDS kataloğu. Lütfen URL'yi kontrol edin.",
"Browse and download books from online catalogs": "Çevrimiçi kataloglardan kitapları görüntüleyin ve indirin",
"My Catalogs": "Kataloglarım",
"Add Catalog": "Katalog Ekle",
"No catalogs yet": "Henüz katalog yok",
"Add your first OPDS catalog to start browsing books": "Kitapları görüntülemeye başlamak için ilk OPDS kataloğunuzu ekleyin",
"Add Your First Catalog": "İlk Kataloğunuzu Ekleyin",
"Browse": "Gözat",
"Popular Catalogs": "Popüler Kataloglar",
"Add": "Ekle",
"Add OPDS Catalog": "OPDS Kataloğu Ekle",
"Catalog Name": "Katalog Adı",
"My Calibre Library": "Calibre Kütüphanem",
"OPDS URL": "OPDS URL",
"Username (optional)": "Kullanıcı Adı (opsiyonel)",
"Password (optional)": "Şifre (opsiyonel)",
"Description (optional)": "Açıklama (opsiyonel)",
"A brief description of this catalog": "Bu katalog hakkında kısa açıklama",
"Validating...": "Doğrulanıyor...",
"View All": "Tümünü Görüntüle",
"Forward": "İleri",
"Home": "Ana Sayfa",
"{{count}} items_one": "{{count}} öğe",
"{{count}} items_other": "{{count}} öğe",
"Download completed": "İndirme tamamlandı",
"Download failed": "İndirme başarısız",
"Open Access": "Açık Erişim",
"Borrow": "Ödünç Al",
"Buy": "Satın Al",
"Subscribe": "Abone Ol",
"Sample": "Örnek",
"Download": "İndir",
"Open & Read": "Aç ve Oku",
"Tags": "Etiketler",
"Tag": "Etiket",
"First": "İlk",
"Previous": "Önceki",
"Next": "Sonraki",
"Last": "Son",
"Cannot Load Page": "Sayfa yüklenemiyor",
"An error occurred": "Bir hata oluştu",
"Online Library": "Çevrimiçi Kütüphane",
"URL must start with http:// or https://": "URL http:// veya https:// ile başlamalıdır",
"Title, Author, Tag, etc...": "Başlık, Yazar, Etiket, vb...",
"Query": "Sorgu",
"Subject": "Konu",
"Enter {{terms}}": "{{terms}} girin",
"No search results found": "Arama sonucu bulunamadı",
"Failed to load OPDS feed: {{status}} {{statusText}}": "OPDS beslemesi yüklenemedi: {{status}} {{statusText}}",
"Search in {{title}}": "{{title}} içinde ara",
"Manage Storage": "Depolamayı Yönet",
"Failed to load files": "Dosyalar yüklenemedi",
"Deleted {{count}} file(s)_one": "{{count}} dosya silindi",
"Deleted {{count}} file(s)_other": "{{count}} dosya silindi",
"Failed to delete {{count}} file(s)_one": "{{count}} dosya silinemedi",
"Failed to delete {{count}} file(s)_other": "{{count}} dosya silinemedi",
"Failed to delete files": "Dosyalar silinemedi",
"Total Files": "Toplam Dosya",
"Total Size": "Toplam Boyut",
"Quota": "Kota",
"Used": "Kullanıldı",
"Files": "Dosyalar",
"Search files...": "Dosyaları ara...",
"Newest First": "En Yeni Önce",
"Oldest First": "En Eski Önce",
"Largest First": "En Büyük Önce",
"Smallest First": "En Küçük Önce",
"Name A-Z": "İsim A-Z",
"Name Z-A": "İsim Z-A",
"{{count}} selected_one": "{{count}} seçili dosya",
"{{count}} selected_other": "{{count}} seçili dosya",
"Delete Selected": "Seçilenleri Sil",
"Created": "Oluşturulma Tarihi",
"No files found": "Dosya bulunamadı",
"No files uploaded yet": "Henüz dosya yüklenmedi",
"files": "dosyalar",
"Page {{current}} of {{total}}": "{{total}} sayfa içinde {{current}}. sayfa",
"Are you sure to delete {{count}} selected file(s)?_one": "Seçilen {{count}} dosyayı silmek istediğinizden emin misiniz?",
"Are you sure to delete {{count}} selected file(s)?_other": "Seçilen {{count}} dosyayı silmek istediğinizden emin misiniz?",
"Cloud Storage Usage": "Bulut Depolama Kullanımı",
"Rename Group": "Grubu Yeniden Adlandır",
"From Directory": "Dizinden",
"Successfully imported {{count}} book(s)_one": "Başarıyla 1 kitap içe aktarıldı",
"Successfully imported {{count}} book(s)_other": "Başarıyla {{count}} kitap içe aktarıldı",
"Count": "Sayım",
"Start Page": "Başlangıç Sayfası",
"Search in OPDS Catalog...": "OPDS Kataloğunda ara...",
"Please log in to use advanced TTS features": "Gelişmiş TTS özelliklerini kullanmak için lütfen giriş yapın",
"Word limit of 30 words exceeded.": "30 kelime sınırı aşıldı.",
"Proofread": "Düzelt",
"Current selection": "Mevcut seçim",
"All occurrences in this book": "Bu kitaptaki tüm geçenler",
"All occurrences in your library": "Kütüphanenizdeki tüm geçenler",
"Selected text:": "Seçili metin:",
"Replace with:": "Şununla değiştir:",
"Enter text...": "Metin girin…",
"Case sensitive:": "Büyük/küçük harfe duyarlı:",
"Scope:": "Kapsam:",
"Selection": "Seçim",
"Library": "Kütüphane",
"Yes": "Evet",
"No": "Hayır",
"Proofread Replacement Rules": "Düzeltme Değiştirme Kuralları",
"Selected Text Rules": "Seçili Metin Kuralları",
"No selected text replacement rules": "Seçili metin için değiştirme kuralı yok",
"Book Specific Rules": "Kitaba Özel Kurallar",
"No book-level replacement rules": "Kitap düzeyinde değiştirme kuralı yok",
"Disable Quick Action": "Hızlı işlemi devre dışı bırak",
"Enable Quick Action on Selection": "Seçimde hızlı işlemi etkinleştir",
"None": "Hiçbiri",
"Annotation Tools": "Not araçları",
"Enable Quick Actions": "Hızlı işlemleri etkinleştir",
"Quick Action": "Hızlı işlem",
"Copy to Notebook": "Deftere kopyala",
"Copy text after selection": "Seçimden sonra metni kopyala",
"Highlight text after selection": "Seçimden sonra metni vurgula",
"Annotate text after selection": "Seçimden sonra metni not al",
"Search text after selection": "Seçimden sonra metni ara",
"Look up text in dictionary after selection": "Seçimden sonra metni sözlükte ara",
"Look up text in Wikipedia after selection": "Seçimden sonra metni Vikipedya'da ara",
"Translate text after selection": "Seçimden sonra metni çevir",
"Read text aloud after selection": "Seçimden sonra metni sesli oku",
"Proofread text after selection": "Seçimden sonra metni düzelt",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} aktif, {{pendingCount}} beklemede",
"{{failedCount}} failed": "{{failedCount}} başarısız",
"Waiting...": "Bekleniyor...",
"Failed": "Başarısız",
"Completed": "Tamamlandı",
"Cancelled": "İptal edildi",
"Retry": "Yeniden dene",
"Active": "Aktif",
"Transfer Queue": "Transfer Kuyruğu",
"Upload All": "Tümünü Yükle",
"Download All": "Tümünü İndir",
"Resume Transfers": "Transferleri Sürdür",
"Pause Transfers": "Transferleri Duraklat",
"Pending": "Beklemede",
"No transfers": "Transfer yok",
"Retry All": "Tümünü Yeniden Dene",
"Clear Completed": "Tamamlananları Temizle",
"Clear Failed": "Başarısızları Temizle",
"Upload queued: {{title}}": "Yükleme sıraya alındı: {{title}}",
"Download queued: {{title}}": "İndirme sıraya alındı: {{title}}",
"Book not found in library": "Kitap kütüphanede bulunamadı",
"Unknown error": "Bilinmeyen hata",
"Please log in to continue": "Devam etmek için giriş yapın",
"Cloud File Transfers": "Bulut Dosya Transferleri",
"Show Search Results": "Arama sonuçlarını göster",
"Search results for '{{term}}'": "'{{term}}' için sonuçlar",
"Close Search": "Aramayı kapat",
"Previous Result": "Önceki sonuç",
"Next Result": "Sonraki sonuç",
"Bookmarks": "Yer İşaretleri",
"Annotations": "Açıklamalar",
"Show Results": "Sonuçları Göster",
"Clear search": "Aramayı temizle",
"Clear search history": "Arama geçmişini temizle",
"Tap to Toggle Footer": "Altbilgiyi değiştirmek için dokunun",
"Exported successfully": "Başarıyla dışa aktarıldı",
"Book exported successfully.": "Kitap başarıyla dışa aktarıldı.",
"Failed to export the book.": "Kitap dışa aktarılamadı.",
"Export Book": "Kitabı Dışa Aktar",
"Whole word:": "Tam kelime:",
"Error": "Hata",
"Unable to load the article. Try searching directly on {{link}}.": "Makale yüklenemiyor. Doğrudan {{link}} üzerinde arama yapmayı deneyin.",
"Unable to load the word. Try searching directly on {{link}}.": "Kelime yüklenemiyor. Doğrudan {{link}} üzerinde arama yapmayı deneyin.",
"Date Published": "Yayın tarihi",
"Only for TTS:": "Sadece TTS için:",
"Uploaded": "Yüklendi",
"Downloaded": "İndirildi",
"Deleted": "Silindi",
"Note:": "Not:",
"Time:": "Saat:",
"Format Options": "Format Seçenekleri",
"Export Date": "Dışa Aktarma Tarihi",
"Chapter Titles": "Bölüm Başlıkları",
"Chapter Separator": "Bölüm Ayracı",
"Highlights": "Vurgular",
"Note Date": "Not Tarihi",
"Advanced": "Gelişmiş",
"Hide": "Gizle",
"Show": "Göster",
"Use Custom Template": "Özel Şablon Kullan",
"Export Template": "Dışa Aktarma Şablonu",
"Template Syntax:": "Şablon Sözdizimi:",
"Insert value": "Değer ekle",
"Format date (locale)": "Tarihi biçimlendir (yerel)",
"Format date (custom)": "Tarihi biçimlendir (özel)",
"Conditional": "Koşullu",
"Loop": "Döngü",
"Available Variables:": "Kullanılabilir Değişkenler:",
"Book title": "Kitap başlığı",
"Book author": "Kitap yazarı",
"Export date": "Dışa aktarma tarihi",
"Array of chapters": "Bölümler dizisi",
"Chapter title": "Bölüm başlığı",
"Array of annotations": "Notlar dizisi",
"Highlighted text": "Vurgulanan metin",
"Annotation note": "Not açıklaması",
"Date Format Tokens:": "Tarih Biçimi Belirteçleri:",
"Year (4 digits)": "Yıl (4 basamak)",
"Month (01-12)": "Ay (01-12)",
"Day (01-31)": "Gün (01-31)",
"Hour (00-23)": "Saat (00-23)",
"Minute (00-59)": "Dakika (00-59)",
"Second (00-59)": "Saniye (00-59)",
"Show Source": "Kaynağı Göster",
"No content to preview": "Önizlenecek içerik yok",
"Export": "Dışa Aktar",
"Set Timeout": "Zaman aşımını ayarla",
"Select Voice": "Ses seç",
"Toggle Sticky Bottom TTS Bar": "Sabit TTS çubuğunu değiştir",
"Display what I'm reading on Discord": "Discord'da okuduğumu göster",
"Show on Discord": "Discord'da göster",
"Instant {{action}}": "Anında {{action}}",
"Instant {{action}} Disabled": "Anında {{action}} Devre Dışı",
"Annotation": "Açıklama",
"Reset Template": "Şablonu Sıfırla",
"Annotation style": "Açıklama stili",
"Annotation color": "Açıklama rengi",
"Annotation time": "Açıklama zamanı",
"AI": "YZ",
"Are you sure you want to re-index this book?": "Bu kitabı yeniden dizinlemek istediğinizden emin misiniz?",
"Enable AI in Settings": "Ayarlarda YZ'yi Etkinleştir",
"Index This Book": "Bu Kitabı Dizinle",
"Enable AI search and chat for this book": "Bu kitap için YZ arama ve sohbeti etkinleştir",
"Start Indexing": "Dizinlemeyi Başlat",
"Indexing book...": "Kitap dizinleniyor...",
"Preparing...": "Hazırlanıyor...",
"Delete this conversation?": "Bu konuşmayı sil?",
"No conversations yet": "Henüz konuşma yok",
"Start a new chat to ask questions about this book": "Bu kitap hakkında soru sormak için yeni bir sohbet başlatın",
"Rename": "Yeniden Adlandır",
"New Chat": "Yeni Sohbet",
"Chat": "Sohbet",
"Please enter a model ID": "Lütfen bir model kimliği girin",
"Model not available or invalid": "Model kullanılamıyor veya geçersiz",
"Failed to validate model": "Model doğrulanamadı",
"Couldn't connect to Ollama. Is it running?": "Ollama'ya bağlanılamadı. Çalışıyor mu?",
"Invalid API key or connection failed": "Geçersiz API anahtarı veya bağlantı başarısız",
"Connection failed": "Bağlantı başarısız",
"AI Assistant": "YZ Asistanı",
"Enable AI Assistant": "YZ Asistanını Etkinleştir",
"Provider": "Sağlayıcı",
"Ollama (Local)": "Ollama (Yerel)",
"AI Gateway (Cloud)": "YZ Geçidi (Bulut)",
"Ollama Configuration": "Ollama Yapılandırması",
"Refresh Models": "Modelleri Yenile",
"AI Model": "YZ Modeli",
"No models detected": "Model algılanmadı",
"AI Gateway Configuration": "YZ Geçidi Yapılandırması",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Yüksek kaliteli, ekonomik YZ modelleri arasından seçim yapın. Aşağıdaki \"Özel Model\"i seçerek kendi modelinizi de kullanabilirsiniz.",
"API Key": "API Anahtarı",
"Get Key": "Anahtar Al",
"Model": "Model",
"Custom Model...": "Özel Model...",
"Custom Model ID": "Özel Model Kimliği",
"Validate": "Doğrula",
"Model available": "Model mevcut",
"Connection": "Bağlantı",
"Test Connection": "Bağlantıyı Test Et",
"Connected": "Bağlandı",
"Custom Colors": "Özel Renkler",
"Color E-Ink Mode": "Renkli E-Ink Modu",
"Reading Ruler": "Okuma Cetveli",
"Enable Reading Ruler": "Okuma Cetvelini Etkinleştir",
"Lines to Highlight": "Vurgulanacak Satırlar",
"Ruler Color": "Cetvel Rengi",
"Command Palette": "Komut Paleti",
"Search settings and actions...": "Ayarları ve eylemleri ara...",
"No results found for": "Şunun için sonuç bulunamadı",
"Type to search settings and actions": "Ayarları ve eylemleri aramak için yazın",
"Recent": "Son kullanılanlar",
"navigate": "gezin",
"select": "seç",
"close": "kapat",
"Search Settings": "Ayarları Ara",
"Page Margins": "Sayfa Kenar Boşlukları",
"AI Provider": "Yapay Zeka Sağlayıcısı",
"Ollama URL": "Ollama URL",
"Ollama Model": "Ollama Modeli",
"AI Gateway Model": "AI Gateway Modeli",
"Actions": "Eylemler",
"Navigation": "Gezinme",
"Set status for {{count}} book(s)_one": "{{count}} kitap için durumu ayarla",
"Set status for {{count}} book(s)_other": "{{count}} kitap için durumu ayarla",
"Mark as Unread": "Okunmadı olarak işaretle",
"Mark as Finished": "Bitirildi olarak işaretle",
"Finished": "Bitirildi",
"Unread": "Okunmadı",
"Clear Status": "Durumu Temizle",
"Status": "Durum",
"Loading": "Yükleniyor...",
"Exit Paragraph Mode": "Paragraf modundan çık",
"Paragraph Mode": "Paragraf modu",
"Embedding Model": "Gömme Modeli",
"{{count}} book(s) synced_one": "{{count}} kitap senkronize edildi",
"{{count}} book(s) synced_other": "{{count}} kitap senkronize edildi",
"Unable to start RSVP": "RSVP başlatılamadı",
"RSVP not supported for PDF": "PDF için RSVP desteklenmiyor",
"Select Chapter": "Bölüm Seç",
"{{number}} WPM": "{{number}} Kelime/Dakika",
"Context": "Bağlam",
"Ready": "Hazır",
"Chapter Progress": "Bölüm İlerlemesi",
"words": "kelime",
"{{time}} left": "{{time}} kaldı",
"Reading progress": "Okuma ilerlemesi",
"Click to seek": "Konum aramak için tıkla",
"Skip back 15 words": "15 kelime geri atla",
"Back 15 words (Shift+Left)": "15 kelime geri (Shift+Sol)",
"Pause (Space)": "Duraklat (Boşluk)",
"Play (Space)": "Oynat (Boşluk)",
"Skip forward 15 words": "15 kelime ileri atla",
"Forward 15 words (Shift+Right)": "15 kelime ileri (Shift+Sağ)",
"Pause:": "Duraklat:",
"Decrease speed": "Hızı azalt",
"Slower (Left/Down)": "Daha yavaş (Sol/Aşağı)",
"Current speed": "Mevcut hız",
"Increase speed": "Hızı artır",
"Faster (Right/Up)": "Daha hızlı (Sağ/Yukarı)",
"Start RSVP Reading": "RSVP Okumasını Başlat",
"Choose where to start reading": "Nereden okumaya başlayacağınızı seçin",
"From Chapter Start": "Bölüm Başından",
"Start reading from the beginning of the chapter": "Bölümün başından itibaren okumaya başla",
"Resume": "Devam Et",
"Continue from where you left off": "Kaldığınız yerden devam edin",
"From Current Page": "Mevcut Sayfadan",
"Start from where you are currently reading": "Şu anda okuduğunuz yerden başlayın",
"From Selection": "Seçimden",
"Speed Reading Mode": "Hızlı Okuma Modu",
"Scroll left": "Sola kaydır",
"Scroll right": "Sağa kaydır",
"Library Sync Progress": "Kütüphane Senkronizasyon İlerlemesi",
"Back to library": "Kütüphaneye dön",
"Group by...": "Şuna göre grupla...",
"Export as Plain Text": "Düz Metin Olarak Dışa Aktar",
"Export as Markdown": "Markdown Olarak Dışa Aktar",
"Show Page Navigation Buttons": "Gezinme düğmeleri",
"Page {{number}}": "Sayfa {{number}}",
"highlight": "vurgula",
"underline": "altı çizili",
"squiggly": "dalgalı",
"red": "kırmızı",
"violet": "menekşe",
"blue": "mavi",
"green": "yeşil",
"yellow": "sarı",
"Select {{style}} style": "{{style}} stilini seç",
"Select {{color}} color": "{{color}} rengini seç",
"Close Book": "Kitabı Kapat",
"Speed Reading": "Hızlı Okuma",
"Close Speed Reading": "Hızlı Okumayı Kapat",
"Authors": "Yazarlar",
"Books": "Kitaplar",
"Groups": "Gruplar",
"Back to TTS Location": "TTS Konumuna Geri Dön"
}
File diff suppressed because it is too large Load Diff
@@ -5,11 +5,9 @@
"Animation": "Hiệu ứng động",
"Annotate": "Chú thích",
"Apply": "Áp dụng",
"Are you sure to delete the selected books?": "Bạn có chắc chắn muốn xóa các sách đã chọn?",
"Auto Mode": "Chế độ tự động",
"Behavior": "Hành vi",
"Book": "Sách",
"Book Cover": "Bìa sách",
"Bookmark": "Đánh dấu",
"Cancel": "Hủy",
"Chapter": "Chương",
@@ -19,7 +17,6 @@
"Confirm Deletion": "Xác nhận xóa",
"Copied to notebook": "Đã sao chép vào sổ ghi chú",
"Copy": "Sao chép",
"Custom CSS": "CSS tùy chỉnh",
"Dark Mode": "Chế độ tối",
"Default": "Mặc định",
"Default Font": "Phông chữ mặc định",
@@ -27,10 +24,8 @@
"Delete": "Xóa",
"Delete Highlight": "Xóa văn bản được đánh dấu",
"Dictionary": "Từ điển",
"Disable Click-to-Flip": "Tắt tính năng nhấp để lật trang",
"Download Readest": "Tải Readest",
"Edit": "Chỉnh sửa",
"Enter your custom CSS here...": "Nhập CSS tùy chỉnh của bạn vào đây...",
"Excerpts": "Trích dẫn",
"Failed to import book(s): {{filenames}}": "Không thể nhập sách: {{filenames}}",
"Fast": "Nhanh",
@@ -43,17 +38,13 @@
"Global Settings": "Cài đặt chung",
"Go Back": "Quay lại",
"Go Forward": "Tiến tới",
"Go Left": "Sang trái",
"Go Right": "Sang phải",
"Grass": "Xanh cỏ",
"Gray": "Xám",
"Gruvbox": "Gruvbox",
"Highlight": "Đánh dấu",
"Horizontal Direction": "Hướng ngang",
"Hyphenation": "Gạch nối từ",
"Identifier:": "Định danh:",
"Import Books": "Nhập sách",
"Language:": "Ngôn ngữ:",
"Layout": "Bố cục",
"Light Mode": "Chế độ sáng",
"Loading...": "Đang tải...",
@@ -64,7 +55,6 @@
"Match Whole Words": "Khớp toàn bộ từ",
"Maximum Number of Columns": "Số cột tối đa",
"Minimum Font Size": "Cỡ chữ tối thiểu",
"Misc": "Khác",
"Monospace Font": "Phông chữ đơn cách",
"More Info": "Thông tin thêm",
"Nord": "Nord",
@@ -76,8 +66,8 @@
"Paging Animation": "Hiệu ứng lật trang",
"Paragraph": "Đoạn văn",
"Parallel Read": "Đọc song song",
"Published:": "Xuất bản:",
"Publisher:": "Nhà xuất bản:",
"Published": "Xuất bản",
"Publisher": "Nhà xuất bản",
"Reading Progress Synced": "Tiến độ đọc đã được đồng bộ",
"Reload Page": "Tải lại trang",
"Reveal in File Explorer": "Hiển thị trong File Explorer",
@@ -91,7 +81,6 @@
"Search...": "Tìm kiếm...",
"Select Book": "Chọn sách",
"Select Books": "Chọn sách",
"Select Multiple Books": "Chọn nhiều sách",
"Sepia": "Nâu cổ",
"Serif Font": "Phông chữ có chân",
"Show Book Details": "Hiển thị chi tiết sách",
@@ -102,17 +91,15 @@
"Slow": "Chậm",
"Solarized": "Solarized",
"Speak": "Đọc",
"Subjects:": "Chủ đề:",
"Subjects": "Chủ đề",
"System Fonts": "Phông chữ hệ thống",
"TTS not supported in this device": "TTS không được hỗ trợ trên thiết bị này",
"Theme Color": "Màu chủ đề",
"Theme Mode": "Chế độ chủ đề",
"Translate": "Dịch",
"Translated Text": "Văn bản dịch",
"Unknown": "Không xác định",
"Untitled": "Không có tiêu đề",
"Updated:": "Cập nhật:",
"User avatar": "Ảnh đại diện",
"Updated": "Cập nhật",
"Version {{version}}": "Phiên bản {{version}}",
"Vertical Direction": "Hướng dọc",
"Welcome to your library. You can import your books here and read them anytime.": "Chào mừng đến với thư viện của bạn. Bạn có thể nhập sách vào đây và đọc bất cứ lúc nào.",
@@ -121,26 +108,21 @@
"Your Library": "Thư viện của bạn",
"TTS not supported for PDF": "TTS không được hỗ trợ cho PDF",
"Override Book Font": "Ghi đè phông chữ sách",
"Vertical Margins (px)": "Lề dọc (px)",
"Horizontal Margins (%)": "Lề ngang (%)",
"Apply to All Books": "Áp dụng cho tất cả sách",
"Apply to This Book": "Áp dụng cho sách này",
"Unable to fetch the translation. Try again later.": "Không thể tải dịch vụ. Vui lòng thử lại sau.",
"Update Now!": "Cập nhật ngay!",
"Update": "Cập nhật",
"Check Update": "Kiểm tra cập nhật",
"Already the latest version": "Đã là phiên bản mới nhất",
"Book Details": "Chi tiết sách",
"From Local File": "Từ tệp địa phương",
"TOC": "Mục lục",
"Table of Contents": "Mục lục",
"Book uploaded: {{title}}": "Sách đã tải lên: {{title}}",
"Failed to upload book: {{title}}": "Không thể tải lên sách: {{title}}",
"Book downloaded: {{title}}": "Sách đã tải về: {{title}}",
"Failed to download book: {{title}}": "Không thể tải về sách: {{title}}",
"Upload Book": "Tải lên sách",
"Auto Upload Books to Cloud": "Tự động tải sách lên đám mây",
"{{percentage}}% of Cloud Storage Used.": "{{percentage}}% dung lượng lưu trữ đám mây đã sử dụng.",
"Storage": "Lưu trữ",
"Book deleted: {{title}}": "Sách đã xóa: {{title}}",
"Failed to delete book: {{title}}": "Không thể xóa sách: {{title}}",
"Check Updates on Start": "Kiểm tra cập nhật khi khởi động",
@@ -172,7 +154,7 @@
"Create a Password": "Tạo mật khẩu",
"Sign up": "Đăng ký",
"Signing up...": "Đang đăng ký...",
"Dont have an account? Sign up": "Chưa có tài khoản? Đăng ký",
"Don't have an account? Sign up": "Chưa có tài khoản? Đăng ký",
"Check your email for the confirmation link": "Kiểm tra email của bạn để nhận liên kết xác nhận",
"Signing in ...": "Đang đăng nhập ...",
"Send a magic link email": "Gửi email liên kết ma thuật",
@@ -191,41 +173,15 @@
"Token": "Mã token",
"Your OTP token": "Mã OTP của bạn",
"Verify token": "Xác minh mã token",
"Sign in with Google": "Đăng nhập với Google",
"Sign in with Apple": "Đăng nhập với Apple",
"Sign in with GitHub": "Đăng nhập với GitHub",
"Account": "Tài khoản",
"Cloud Storage": "Lưu trữ đám mây",
"Failed to delete user. Please try again later.": "Không thể xóa người dùng. Vui lòng thử lại sau.",
"Unlimited Offline/Online Reading": "Đọc ngoại tuyến/trực tuyến không giới hạn",
"Unlimited Cloud Sync Devices": "Đồng bộ hóa thiết bị đám mây không giới hạn",
"Essential Text-to-Speech Voices": "Giọng nói chuyển văn bản thành giọng nói cơ bản",
"DeepL Free Access": "Truy cập DeepL miễn phí",
"Community Support": "Hỗ trợ cộng đồng",
"500 MB Cloud Sync Space": "500 MB không gian đồng bộ hóa đám mây",
"Includes All Free Tier Benefits": "Bao gồm tất cả lợi ích của gói miễn phí",
"AI Summaries": "Tóm tắt AI",
"AI Translations": "Dịch thuật AI",
"Priority Support": "Hỗ trợ ưu tiên",
"DeepL Pro Access": "Truy cập DeepL Pro",
"Expanded Text-to-Speech Voices": "Giọng nói chuyển văn bản thành giọng nói mở rộng",
"2000 MB Cloud Sync Space": "2000 MB không gian đồng bộ hóa đám mây",
"Includes All Plus Tier Benefits": "Bao gồm tất cả lợi ích của gói Plus",
"Unlimited AI Summaries": "Tóm tắt AI không giới hạn",
"Unlimited AI Translations": "Dịch thuật AI không giới hạn",
"Unlimited DeepL Pro Access": "Truy cập DeepL Pro không giới hạn",
"Advanced AI Tools": "Công cụ AI nâng cao",
"Early Feature Access": "Truy cập tính năng sớm",
"10 GB Cloud Sync Space": "10 GB không gian đồng bộ hóa đám mây",
"Loading profile...": "Đang tải hồ sơ...",
"Features": "Tính năng",
"Delete Account": "Xóa tài khoản",
"Delete Your Account?": "Xóa tài khoản của bạn?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "Hành động này không thể hoàn tác. Tất cả dữ liệu của bạn trên đám mây sẽ bị xóa vĩnh viễn.",
"Delete Permanently": "Xóa vĩnh viễn",
"Free Tier": "Gói miễn phí",
"Plus Tier": "Gói Plus",
"Pro Tier": "Gói Pro",
"RTL Direction": "Hướng RTL",
"Maximum Column Height": "Chiều cao cột tối đa",
"Maximum Column Width": "Chiều rộng cột tối đa",
@@ -234,7 +190,7 @@
"No supported files found. Supported formats: {{formats}}": "Không tìm thấy tệp được hỗ trợ. Định dạng được hỗ trợ: {{formats}}",
"Drop to Import Books": "Kéo và thả để nhập sách",
"Custom": "Tùy chỉnh",
"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": "Cả thế giới này là một sân khấu,\nVà tất cả đàn ông và phụ nữ chỉ là những diễn viên;\nHọ có cửa ra và cửa vào của mình,\nVà một người trong cuộc đời mình đóng nhiều vai,\nHành động của mình là bảy tuổi.\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": "Cả thế giới này là một sân khấu,\nVà tất cả đàn ông và phụ nữ chỉ là những diễn viên;\nHọ có cửa ra và cửa vào của mình,\nVà một người trong cuộc đời mình đóng nhiều vai,\nHành động của mình là bảy tuổi.\n\n— William Shakespeare",
"Custom Theme": "Chủ đề tùy chỉnh",
"Theme Name": "Tên chủ đề",
"Text Color": "Màu văn bản",
@@ -259,11 +215,809 @@
"Copied to clipboard": "Đã sao chép vào bảng ghi",
"Export Annotations": "Xuất chú thích",
"Auto Import on File Open": "Tự động nhập khi mở tệp",
"LXGW WenKai GB Screen": "LXGW WenKai",
"Swap Click-to-Flip Area": "Hoán đổi khu vực nhấp để lật trang",
"No chapters detected.": "Không phát hiện thấy chương nào.",
"Failed to parse the EPUB file.": "Không thể phân tích tệp EPUB.",
"This book format is not supported.": "Định dạng sách này không được hỗ trợ.",
"LXGW WenKai GB Screen": "LXGW WenKai SC",
"LXGW WenKai TC": "LXGW WenKai TC",
"No chapters detected": "Không phát hiện thấy chương nào",
"Failed to parse the EPUB file": "Không thể phân tích tệp EPUB",
"This book format is not supported": "Định dạng sách này không được hỗ trợ",
"Unable to fetch the translation. Please log in first and try again.": "Không thể tải dịch vụ. Vui lòng đăng nhập trước và thử lại.",
"Group": "Nhóm"
"Group": "Nhóm",
"Always on Top": "Luôn ở trên cùng",
"No Timeout": "Không có thời gian chờ",
"{{value}} minute": "{{value}} phút",
"{{value}} minutes": "{{value}} phút",
"{{value}} hour": "{{value}} giờ",
"{{value}} hours": "{{value}} giờ",
"CJK Font": "Phông chữ CJK",
"Clear Search": "Xóa tìm kiếm",
"Header & Footer": "Đầu trang & Chân trang",
"Apply also in Scrolled Mode": "Áp dụng cũng trong chế độ cuộn",
"A new version of Readest is available!": "Đã có phiên bản mới của Readest!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} đã có sẵn (phiên bản đã cài đặt {{currentVersion}}).",
"Download and install now?": "Tải xuống và cài đặt ngay bây giờ?",
"Downloading {{downloaded}} of {{contentLength}}": "Đang tải {{downloaded}} trong {{contentLength}}",
"Download finished": "Tải xuống hoàn tất",
"DOWNLOAD & INSTALL": "TẢI XUỐNG & CÀI ĐẶT",
"Changelog": "Thay đổi",
"Software Update": "Cập nhật phần mềm",
"Title": "Tiêu đề",
"Date Read": "Ngày đã đọc",
"Date Added": "Ngày thêm",
"Format": "Định dạng",
"Ascending": "Tăng dần",
"Descending": "Giảm dần",
"Sort by...": "Sắp xếp theo...",
"Added": "Đã thêm",
"GuanKiapTsingKhai-T": "GuanKiapTsingKhai-T",
"Description": "Miêu tả",
"No description available": "Không có mô tả nào",
"List": "Danh sách",
"Grid": "Lưới",
"(from 'As You Like It', Act II)": "(từ 'Như bạn thích', Hành động II)",
"Link Color": "Màu liên kết",
"Volume Keys for Page Flip": "Phím âm lượng để lật trang",
"Screen": "Màn hình",
"Orientation": "Định hướng",
"Portrait": "Chân dung",
"Landscape": "Phong cảnh",
"Open Last Book on Start": "Mở sách cuối cùng khi khởi động",
"Checking for updates...": "Đang kiểm tra cập nhật...",
"Error checking for updates": "Lỗi khi kiểm tra cập nhật",
"Details": "Chi tiết",
"File Size": "Kích thước tệp",
"Auto Detect": "Phát hiện tự động",
"Next Section": "Phần tiếp theo",
"Previous Section": "Phần trước",
"Next Page": "Trang tiếp theo",
"Previous Page": "Trang trước",
"Are you sure to delete {{count}} selected book(s)?_other": "Bạn có chắc muốn xóa {{count}} cuốn sách đã chọn không?",
"Are you sure to delete the selected book?": "Bạn có chắc muốn xóa cuốn sách đã chọn không?",
"Deselect": "Bỏ chọn",
"Select All": "Chọn tất",
"No translation available.": "Không có bản dịch nào.",
"Translated by {{provider}}.": "Được dịch bởi {{provider}}.",
"DeepL": "DeepL",
"Google Translate": "Google Dịch",
"Azure Translator": "Azure Translator",
"Invert Image In Dark Mode": "Đảo ảnh chế độ tối",
"Help improve Readest": "Giúp cải thiện Readest",
"Sharing anonymized statistics": "Chia sẻ thống kê ẩn danh",
"Interface Language": "Ngôn ngữ giao diện",
"Translation": "Dịch",
"Enable Translation": "Bật dịch",
"Translation Service": "Dịch vụ dịch thuật",
"Translate To": "Dịch sang",
"Disable Translation": "Tắt dịch",
"Scroll": "Cuộn",
"Overlap Pixels": "Chồng lấn pixel",
"System Language": "Ngôn ngữ hệ thống",
"Security": "An ninh",
"Allow JavaScript": "Cho phép JavaScript",
"Enable only if you trust the file.": "Chỉ bật nếu bạn tin tưởng tệp.",
"Sort TOC by Page": "Sort Mục lục theo Trang",
"Search in {{count}} Book(s)..._other": "Tìm kiếm trong {{count}} cuốn sách...",
"No notes match your search": "Không tìm thấy ghi chú nào",
"Search notes and excerpts...": "Tìm ghi chú...",
"Sign in to Sync": "Đăng nhập",
"Synced at {{time}}": "Đã đồng bộ lúc {{time}}",
"Never synced": "Chưa từng đồng bộ",
"Show Remaining Time": "Hiển thị thời gian còn lại",
"{{time}} min left in chapter": "{{time}} phút còn lại trong chương",
"Override Book Color": "Đổi màu sách",
"Login Required": "Cần đăng nhập",
"Quota Exceeded": "Vượt hạn mức",
"{{percentage}}% of Daily Translation Characters Used.": "{{percentage}}% số ký tự dịch hàng ngày đã sử dụng.",
"Translation Characters": "Những ký tự dịch",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}} giọng",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "Đã xảy ra sự cố. Đừng lo, nhóm của chúng tôi đã được thông báo và chúng tôi đang làm việc để sửa chữa.",
"Error Details:": "Chi tiết lỗi:",
"Try Again": "Thử lại",
"Need help?": "Bạn cần giúp đỡ?",
"Contact Support": "Liên hệ hỗ trợ",
"Code Highlighting": "Đánh dấu mã",
"Enable Highlighting": "Cho phép đánh dấu",
"Code Language": "Ngôn ngữ mã",
"Top Margin (px)": "Lề trên (px)",
"Bottom Margin (px)": "Lề dưới (px)",
"Right Margin (px)": "Lề phải (px)",
"Left Margin (px)": "Lề trái (px)",
"Column Gap (%)": "Khoảng cách cột (%)",
"Always Show Status Bar": "Luôn hiển thị thanh trạng thái",
"Custom Content CSS": "CSS nội dung",
"Enter CSS for book content styling...": "Nhập CSS cho phần nội dung sách...",
"Custom Reader UI CSS": "CSS giao diện đọc",
"Enter CSS for reader interface styling...": "Nhập CSS cho giao diện trình đọc...",
"Crop": "Cắt",
"Book Covers": "Bìa sách",
"Fit": "Vừa vặn",
"Reset {{settings}}": "Đặt lại {{settings}}",
"Reset Settings": "Đặt lại cài đặt",
"{{count}} pages left in chapter_other": "Còn {{count}} trang trong chương",
"Show Remaining Pages": "Hiển thị trang còn lại",
"Source Han Serif CN": "Source Han Serif",
"Huiwen-MinchoGBK": "Huiwen Mincho",
"KingHwa_OldSong": "KingHwa Song",
"Manage Subscription": "Quản lý đăng ký",
"Coming Soon": "Sắp ra mắt",
"Upgrade to {{plan}}": "Nâng cấp lên {{plan}}",
"Upgrade to Plus or Pro": "Nâng cấp lên Plus hoặc Pro",
"Current Plan": "Gói hiện tại",
"Plan Limits": "Giới hạn gói",
"Processing your payment...": "Đang xử lý thanh toán...",
"Please wait while we confirm your subscription.": "Vui lòng chờ trong khi chúng tôi xác nhận đăng ký của bạn.",
"Payment Processing": "Đang xử lý thanh toán",
"Your payment is being processed. This usually takes a few moments.": "Thanh toán của bạn đang được xử lý. Thường mất vài giây.",
"Payment Failed": "Thanh toán thất bại",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "Chúng tôi không thể xử lý đăng ký của bạn. Vui lòng thử lại hoặc liên hệ hỗ trợ nếu sự cố tiếp tục.",
"Back to Profile": "Quay lại hồ sơ",
"Subscription Successful!": "Đăng ký thành công!",
"Thank you for your subscription! Your payment has been processed successfully.": "Cảm ơn bạn đã đăng ký! Thanh toán của bạn đã được xử lý thành công.",
"Email:": "Email:",
"Plan:": "Gói:",
"Amount:": "Số tiền:",
"Go to Library": "Đi đến Thư viện",
"Need help? Contact our support team at support@readest.com": "Cần hỗ trợ? Liên hệ nhóm hỗ trợ tại support@readest.com",
"Free Plan": "Gói miễn phí",
"month": "tháng",
"AI Translations (per day)": "Dịch AI (mỗi ngày)",
"Plus Plan": "Gói Plus",
"Includes All Free Plan Benefits": "Bao gồm tất cả lợi ích của gói miễn phí",
"Pro Plan": "Gói Pro",
"More AI Translations": "Thêm dịch AI",
"Complete Your Subscription": "Hoàn tất đăng ký của bạn",
"{{percentage}}% of Cloud Sync Space Used.": "Đã sử dụng {{percentage}}% không gian đồng bộ đám mây.",
"Cloud Sync Storage": "Lưu trữ đồng bộ đám mây",
"Disable": "Tắt",
"Enable": "Bật",
"Upgrade to Readest Premium": "Đăng ký Readest Premium",
"Show Source Text": "Hiển thị văn bản gốc",
"Cross-Platform Sync": "Đồng Bộ Đa Nền Tảng",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "Đồng bộ liền mạch thư viện, tiến độ, đánh dấu và ghi chú trên tất cả thiết bị—không bao giờ mất vị trí đọc nữa.",
"Customizable Reading": "Đọc Tùy Chỉnh",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "Cá nhân hóa mọi chi tiết với phông chữ, bố cục, chủ đề có thể điều chỉnh và cài đặt hiển thị nâng cao cho trải nghiệm đọc hoàn hảo.",
"AI Read Aloud": "AI Đọc To",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "Thưởng thức việc đọc rảnh tay với giọng AI tự nhiên làm sống động sách của bạn.",
"AI Translations": "Dịch Thuật AI",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "Dịch bất kỳ văn bản nào ngay lập tức với sức mạnh của Google, Azure hoặc DeepL—hiểu nội dung bằng mọi ngôn ngữ.",
"Connect with fellow readers and get help fast in our friendly community channels.": "Kết nối với độc giả khác và nhận trợ giúp nhanh chóng trong các kênh cộng đồng thân thiện.",
"Unlimited AI Read Aloud Hours": "Giờ Đọc To AI Không Giới Hạn",
"Listen without limits—convert as much text as you like into immersive audio.": "Nghe không giới hạn—chuyển đổi bao nhiêu văn bản bạn muốn thành âm thanh sống động.",
"Unlock enhanced translation capabilities with more daily usage and advanced options.": "Mở khóa khả năng dịch thuật nâng cao với nhiều lượt sử dụng hàng ngày và tùy chọn nâng cao.",
"DeepL Pro Access": "Truy Cập DeepL Pro",
"Enjoy faster responses and dedicated assistance whenever you need help.": "Tận hưởng phản hồi nhanh hơn và hỗ trợ chuyên biệt khi bạn cần giúp đỡ.",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "Đã đạt hạn ngạch dịch thuật hàng ngày. Nâng cấp gói để tiếp tục sử dụng dịch thuật AI.",
"Includes All Plus Plan Benefits": "Bao Gồm Tất Cả Lợi Ích Gói Plus",
"Early Feature Access": "Truy Cập Tính Năng Sớm",
"Be the first to explore new features, updates, and innovations before anyone else.": "Khám phá tính năng mới, cập nhật và đổi mới trước người khác.",
"Advanced AI Tools": "Công Cụ AI Nâng Cao",
"Harness powerful AI tools for smarter reading, translation, and content discovery.": "Khai thác công cụ AI mạnh mẽ cho đọc thông minh, dịch thuật và khám phá nội dung.",
"Translate up to 100,000 characters daily with the most accurate translation engine available.": "Dịch tới 100.000 ký tự hàng ngày với công cụ dịch chính xác nhất hiện có.",
"Translate up to 500,000 characters daily with the most accurate translation engine available.": "Dịch tới 500.000 ký tự hàng ngày với công cụ dịch chính xác nhất hiện có.",
"Securely store and access your entire reading collection with up to 5 GB of cloud storage.": "Lưu trữ và truy cập an toàn toàn bộ bộ sưu tập đọc với tới 5 GB lưu trữ đám mây.",
"Securely store and access your entire reading collection with up to 20 GB of cloud storage.": "Lưu trữ và truy cập an toàn toàn bộ bộ sưu tập đọc với tới 20 GB lưu trữ đám mây.",
"Deleted cloud backup of the book: {{title}}": "Đã xóa bản sao lưu đám mây của sách: {{title}}",
"Are you sure to delete the cloud backup of the selected book?": "Bạn có chắc chắn muốn xóa bản sao lưu đám mây của sách đã chọn không?",
"What's New in Readest": "Những gì mới trong Readest",
"Enter book title": "Nhập tiêu đề sách",
"Subtitle": "Phụ đề",
"Enter book subtitle": "Nhập phụ đề sách",
"Enter author name": "Nhập tên tác giả",
"Series": "Bộ sách",
"Enter series name": "Nhập tên bộ sách",
"Series Index": "Số thứ tự trong bộ",
"Enter series index": "Nhập số thứ tự trong bộ",
"Total in Series": "Tổng số trong bộ",
"Enter total books in series": "Nhập tổng số sách trong bộ",
"Enter publisher": "Nhập nhà xuất bản",
"Publication Date": "Ngày xuất bản",
"Identifier": "Định danh",
"Enter book description": "Nhập mô tả sách",
"Change cover image": "Thay đổi ảnh bìa",
"Replace": "Thay thế",
"Unlock cover": "Mở khóa bìa",
"Lock cover": "Khóa bìa",
"Auto-Retrieve Metadata": "Tự động lấy siêu dữ liệu",
"Auto-Retrieve": "Tự động lấy",
"Unlock all fields": "Mở khóa tất cả trường",
"Unlock All": "Mở khóa tất cả",
"Lock all fields": "Khóa tất cả trường",
"Lock All": "Khóa tất cả",
"Reset": "Đặt lại",
"Edit Metadata": "Chỉnh sửa siêu dữ liệu",
"Locked": "Đã khóa",
"Select Metadata Source": "Chọn nguồn siêu dữ liệu",
"Keep manual input": "Giữ nhập liệu thủ công",
"Google Books": "Google Books",
"Open Library": "Open Library",
"Fiction, Science, History": "Tiểu thuyết, Khoa học, Lịch sử",
"Open Book in New Window": "Mở Sách trong Cửa sổ Mới",
"Voices for {{lang}}": "Giọng nói cho {{lang}}",
"Yandex Translate": "Yandex Dịch",
"YYYY or YYYY-MM-DD": "YYYY hoặc YYYY-MM-DD",
"Restore Purchase": "Khôi phục mua hàng",
"No purchases found to restore.": "Không tìm thấy giao dịch mua nào để khôi phục.",
"Failed to restore purchases.": "Khôi phục giao dịch mua không thành công.",
"Failed to manage subscription.": "Quản lý đăng ký không thành công.",
"Failed to load subscription plans.": "Tải kế hoạch đăng ký không thành công.",
"year": "năm",
"Failed to create checkout session": "Không thể tạo phiên làm việc thanh toán",
"Storage": "Lưu trữ",
"Terms of Service": "Điều khoản dịch vụ",
"Privacy Policy": "Chính sách bảo mật",
"Disable Double Click": "Tắt Nhấp Đôi",
"TTS not supported for this document": "TTS không được hỗ trợ cho tài liệu này",
"Reset Password": "Đặt lại mật khẩu",
"Show Reading Progress": "Hiển thị tiến độ đọc",
"Reading Progress Style": "Phong cách tiến độ đọc",
"Page Number": "Số trang",
"Percentage": "Phần trăm",
"Deleted local copy of the book: {{title}}": "Đã xóa bản sao cục bộ của sách: {{title}}",
"Failed to delete cloud backup of the book: {{title}}": "Không thể xóa bản sao lưu đám mây của sách: {{title}}",
"Failed to delete local copy of the book: {{title}}": "Không thể xóa bản sao cục bộ của sách: {{title}}",
"Are you sure to delete the local copy of the selected book?": "Bạn có chắc chắn muốn xóa bản sao cục bộ của cuốn sách đã chọn không?",
"Remove from Cloud & Device": "Xóa khỏi Đám mây & Thiết bị",
"Remove from Cloud Only": "Xóa chỉ khỏi Đám mây",
"Remove from Device Only": "Xóa chỉ khỏi Thiết bị",
"Disconnected": "Mất kết nối",
"KOReader Sync Settings": "Cài đặt đồng bộ KOReader",
"Sync Strategy": "Chiến lược đồng bộ",
"Ask on conflict": "Hỏi khi có xung đột",
"Always use latest": "Luôn sử dụng phiên bản mới nhất",
"Send changes only": "Chỉ gửi thay đổi",
"Receive changes only": "Chỉ nhận thay đổi",
"Checksum Method": "Phương pháp kiểm tra",
"File Content (recommended)": "Nội dung tệp (được khuyến nghị)",
"File Name": "Tên tệp",
"Device Name": "Tên thiết bị",
"Connect to your KOReader Sync server.": "Kết nối với máy chủ đồng bộ KOReader của bạn.",
"Server URL": "URL máy chủ",
"Username": "Tên người dùng",
"Your Username": "Tên người dùng của bạn",
"Password": "Mật khẩu",
"Connect": "Kết nối",
"KOReader Sync": "Đồng bộ KOReader",
"Sync Conflict": "Xung đột đồng bộ",
"Sync reading progress from \"{{deviceName}}\"?": "Đồng bộ tiến độ đọc từ \"{{deviceName}}\"?",
"another device": "thiết bị khác",
"Local Progress": "Tiến độ cục bộ",
"Remote Progress": "Tiến độ từ xa",
"Page {{page}} of {{total}} ({{percentage}}%)": "Trang {{page}} của {{total}} ({{percentage}}%)",
"Current position": "Vị trí hiện tại",
"Approximately page {{page}} of {{total}} ({{percentage}}%)": "Khoảng trang {{page}} của {{total}} ({{percentage}}%)",
"Approximately {{percentage}}%": "Khoảng {{percentage}}%",
"Failed to connect": "Không thể kết nối",
"Sync Server Connected": "Máy chủ đồng bộ đã kết nối",
"Sync as {{userDisplayName}}": "Đồng bộ dưới tên {{userDisplayName}}",
"Custom Fonts": "Phông Chữ Tùy Chỉnh",
"Cancel Delete": "Hủy Xóa",
"Import Font": "Nhập Phông Chữ",
"Delete Font": "Xóa Phông Chữ",
"Tips": "Mẹo",
"Custom fonts can be selected from the Font Face menu": "Phông chữ tùy chỉnh có thể được chọn từ menu Phông Chữ",
"Manage Custom Fonts": "Quản Lý Phông Chữ Tùy Chỉnh",
"Select Files": "Chọn Tệp",
"Select Image": "Chọn Hình Ảnh",
"Select Video": "Chọn Video",
"Select Audio": "Chọn Âm Thanh",
"Select Fonts": "Chọn Phông Chữ",
"Supported font formats: .ttf, .otf, .woff, .woff2": "Định dạng phông chữ được hỗ trợ: .ttf, .otf, .woff, .woff2",
"Push Progress": "Đẩy tiến độ",
"Pull Progress": "Kéo tiến độ",
"Previous Paragraph": "Đoạn trước",
"Previous Sentence": "Câu trước",
"Pause": "Tạm dừng",
"Play": "Phát",
"Next Sentence": "Câu tiếp theo",
"Next Paragraph": "Đoạn tiếp theo",
"Separate Cover Page": "Trang Bìa Riêng",
"Resize Notebook": "Thay Đổi Kích Thước Sổ Ghi Chép",
"Resize Sidebar": "Thay Đổi Kích Thước Thanh Bên",
"Get Help from the Readest Community": "Nhận Trợ Giúp từ Cộng Đồng Readest",
"Remove cover image": "Xóa ảnh bìa",
"Bookshelf": "Kệ sách",
"View Menu": "Xem menu",
"Settings Menu": "Menu cài đặt",
"View account details and quota": "Xem chi tiết tài khoản và hạn mức",
"Library Header": "Tiêu đề thư viện",
"Book Content": "Nội dung sách",
"Footer Bar": "Thanh chân trang",
"Header Bar": "Thanh đầu trang",
"View Options": "Tùy chọn xem",
"Book Menu": "Menu sách",
"Search Options": "Tùy chọn tìm kiếm",
"Close": "Đóng",
"Delete Book Options": "Tùy chọn xóa sách",
"ON": "BẬT",
"OFF": "TẮT",
"Reading Progress": "Tiến độ đọc",
"Page Margin": "Lề trang",
"Remove Bookmark": "Xóa đánh dấu",
"Add Bookmark": "Thêm đánh dấu",
"Books Content": "Nội dung sách",
"Jump to Location": "Nhảy đến vị trí",
"Unpin Notebook": "Bỏ ghim sổ tay",
"Pin Notebook": "Ghim sổ tay",
"Hide Search Bar": "Ẩn thanh tìm kiếm",
"Show Search Bar": "Hiện thanh tìm kiếm",
"On {{current}} of {{total}} page": "Trên {{current}} của {{total}} trang",
"Section Title": "Tiêu đề phần",
"Decrease": "Giảm",
"Increase": "Tăng",
"Settings Panels": "Các bảng điều khiển cài đặt",
"Settings": "Cài đặt",
"Unpin Sidebar": "Bỏ ghim thanh bên",
"Pin Sidebar": "Ghim thanh bên",
"Toggle Sidebar": "Chuyển đổi thanh bên",
"Toggle Translation": "Chuyển đổi dịch thuật",
"Translation Disabled": "Dịch thuật đã tắt",
"Minimize": "Thu nhỏ",
"Maximize or Restore": "Tối đa hóa hoặc Khôi phục",
"Exit Parallel Read": "Thoát Đọc Song Song",
"Enter Parallel Read": "Vào Đọc Song Song",
"Zoom Level": "Độ phóng to",
"Zoom Out": "Thu nhỏ",
"Reset Zoom": "Đặt lại độ phóng to",
"Zoom In": "Phóng to",
"Zoom Mode": "Chế độ phóng to",
"Single Page": "Một trang",
"Auto Spread": "Tự động trải rộng",
"Fit Page": "Vừa trang",
"Fit Width": "Vừa chiều rộng",
"Failed to select directory": "Không thể chọn thư mục",
"The new data directory must be different from the current one.": "Thư mục dữ liệu mới phải khác với thư mục hiện tại.",
"Migration failed: {{error}}": "Di chuyển không thành công: {{error}}",
"Change Data Location": "Thay đổi vị trí dữ liệu",
"Current Data Location": "Vị trí dữ liệu hiện tại",
"Total size: {{size}}": "Tổng kích thước: {{size}}",
"Calculating file info...": "Đang tính toán thông tin tệp...",
"New Data Location": "Vị trí dữ liệu mới",
"Choose Different Folder": "Chọn thư mục khác",
"Choose New Folder": "Chọn thư mục mới",
"Migrating data...": "Đang di chuyển dữ liệu...",
"Copying: {{file}}": "Đang sao chép: {{file}}",
"{{current}} of {{total}} files": "{{current}} của {{total}} tệp",
"Migration completed successfully!": "Di chuyển hoàn tất thành công!",
"Your data has been moved to the new location. Please restart the application to complete the process.": "Dữ liệu của bạn đã được chuyển đến vị trí mới. Vui lòng khởi động lại ứng dụng để hoàn tất quá trình.",
"Migration failed": "Di chuyển không thành công",
"Important Notice": "Thông báo quan trọng",
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Điều này sẽ di chuyển tất cả dữ liệu ứng dụng của bạn đến vị trí mới. Hãy chắc chắn rằng đích đến có đủ không gian trống.",
"Restart App": "Khởi động lại ứng dụng",
"Start Migration": "Bắt đầu di chuyển",
"Advanced Settings": "Cài đặt nâng cao",
"File count: {{size}}": "Số lượng tệp: {{size}}",
"Background Read Aloud": "Đọc To Nền",
"Ready to read aloud": "Sẵn sàng để đọc to",
"Read Aloud": "Đọc To",
"Screen Brightness": "Độ sáng màn hình",
"Background Image": "Ảnh nền",
"Import Image": "Nhập ảnh",
"Opacity": "Độ mờ",
"Size": "Kích thước",
"Cover": "Bìa",
"Contain": "Chứa",
"{{number}} pages left in chapter": "Còn {{number}} trang trong chương",
"Device": "Thiết bị",
"E-Ink Mode": "Chế độ E-Ink",
"Highlight Colors": "Màu nổi bật",
"Auto Screen Brightness": "Độ sáng màn hình tự động",
"Pagination": "Phân trang",
"Disable Double Tap": "Vô hiệu hóa chạm hai lần",
"Tap to Paginate": "Chạm để phân trang",
"Click to Paginate": "Nhấp để phân trang",
"Tap Both Sides": "Chạm vào cả hai bên",
"Click Both Sides": "Nhấp vào cả hai bên",
"Swap Tap Sides": "Đổi bên chạm",
"Swap Click Sides": "Đổi bên nhấp",
"Source and Translated": "Nguồn và Đã dịch",
"Translated Only": "Chỉ Đã dịch",
"Source Only": "Chỉ Nguồn",
"TTS Text": "Văn bản TTS",
"The book file is corrupted": "Tệp sách bị hỏng",
"The book file is empty": "Tệp sách trống",
"Failed to open the book file": "Không thể mở tệp sách",
"On-Demand Purchase": "Mua theo yêu cầu",
"Full Customization": "Tùy chỉnh đầy đủ",
"Lifetime Plan": "Kế hoạch trọn đời",
"One-Time Payment": "Thanh toán một lần",
"Make a single payment to enjoy lifetime access to specific features on all devices. Purchase specific features or services only when you need them.": "Thực hiện một khoản thanh toán duy nhất để tận hưởng quyền truy cập trọn đời vào các tính năng cụ thể trên tất cả các thiết bị. Mua các tính năng hoặc dịch vụ cụ thể chỉ khi bạn cần chúng.",
"Expand Cloud Sync Storage": "Mở rộng dung lượng lưu trữ đồng bộ hóa đám mây",
"Expand your cloud storage forever with a one-time purchase. Each additional purchase adds more space.": "Mở rộng dung lượng lưu trữ đám mây của bạn mãi mãi với một lần mua. Mỗi lần mua thêm sẽ thêm không gian.",
"Unlock All Customization Options": "Mở khóa tất cả tùy chọn tùy chỉnh",
"Unlock additional themes, fonts, layout options and read aloud, translators, cloud storage services.": "Mở khóa các chủ đề, phông chữ, tùy chọn bố cục và đọc to, dịch giả, dịch vụ lưu trữ đám mây bổ sung.",
"Purchase Successful!": "Mua hàng thành công!",
"lifetime": "trọn đời",
"Thank you for your purchase! Your payment has been processed successfully.": "Cảm ơn bạn đã mua hàng! Thanh toán của bạn đã được xử lý thành công.",
"Order ID:": "Mã đơn hàng:",
"TTS Highlighting": "Đánh dấu TTS",
"Style": "Kiểu",
"Underline": "Gạch chân",
"Strikethrough": "Gạch ngang",
"Squiggly": "Gạch ngoằn ngoèo",
"Outline": "Đường viền",
"Save Current Color": "Lưu màu hiện tại",
"Quick Colors": "Màu nhanh",
"Highlighter": "Bút đánh dấu",
"Save Book Cover": "Lưu bìa sách",
"Auto-save last book cover": "Tự động lưu bìa sách cuối cùng",
"Back": "Quay lại",
"Confirmation email sent! Please check your old and new email addresses to confirm the change.": "Email xác nhận đã được gửi! Vui lòng kiểm tra địa chỉ email cũ và mới của bạn để xác nhận thay đổi.",
"Failed to update email": "Cập nhật email thất bại",
"New Email": "Email mới",
"Your new email": "Email mới của bạn",
"Updating email ...": "Đang cập nhật email ...",
"Update email": "Cập nhật email",
"Current email": "Email hiện tại",
"Update Email": "Cập nhật email",
"All": "Tất cả",
"Unable to open book": "Không thể mở sách",
"Punctuation": "Dấu câu",
"Replace Quotation Marks": "Thay thế dấu ngoặc kép",
"Enabled only in vertical layout.": "Chỉ bật trong bố cục dọc.",
"No Conversion": "Không chuyển đổi",
"Simplified to Traditional": "Giản thể → Phồn thể",
"Traditional to Simplified": "Phồn thể → Giản thể",
"Simplified to Traditional (Taiwan)": "Giản thể → Phồn thể (Đài Loan)",
"Simplified to Traditional (Hong Kong)": "Giản thể → Phồn thể (Hồng Kông)",
"Simplified to Traditional (Taiwan), with phrases": "Giản thể → Phồn thể (Đài Loan • cụm từ)",
"Traditional (Taiwan) to Simplified": "Phồn thể (Đài Loan) → Giản thể",
"Traditional (Hong Kong) to Simplified": "Phồn thể (Hồng Kông) → Giản thể",
"Traditional (Taiwan) to Simplified, with phrases": "Phồn thể (Đài Loan • cụm từ) → Giản thể",
"Convert Simplified and Traditional Chinese": "Chuyển đổi Trung giản/Phồn thể",
"Convert Mode": "Chế độ chuyển đổi",
"Failed to auto-save book cover for lock screen: {{error}}": "Không thể tự động lưu bìa sách cho màn hình khóa: {{error}}",
"Download from Cloud": "Tải xuống từ đám mây",
"Upload to Cloud": "Tải lên đám mây",
"Clear Custom Fonts": "Xóa phông chữ tùy chỉnh",
"Columns": "Cột",
"OPDS Catalogs": "Danh mục OPDS",
"Adding LAN addresses is not supported in the web app version.": "Việc thêm địa chỉ LAN không được hỗ trợ trong phiên bản web.",
"Invalid OPDS catalog. Please check the URL.": "Danh mục OPDS không hợp lệ. Vui lòng kiểm tra URL.",
"Browse and download books from online catalogs": "Duyệt và tải sách từ các danh mục trực tuyến",
"My Catalogs": "Danh mục của tôi",
"Add Catalog": "Thêm danh mục",
"No catalogs yet": "Chưa có danh mục nào",
"Add your first OPDS catalog to start browsing books": "Thêm danh mục OPDS đầu tiên để bắt đầu duyệt sách",
"Add Your First Catalog": "Thêm danh mục đầu tiên",
"Browse": "Duyệt",
"Popular Catalogs": "Danh mục phổ biến",
"Add": "Thêm",
"Add OPDS Catalog": "Thêm danh mục OPDS",
"Catalog Name": "Tên danh mục",
"My Calibre Library": "Thư viện Calibre của tôi",
"OPDS URL": "URL OPDS",
"Username (optional)": "Tên đăng nhập (tùy chọn)",
"Password (optional)": "Mật khẩu (tùy chọn)",
"Description (optional)": "Mô tả (tùy chọn)",
"A brief description of this catalog": "Mô tả ngắn gọn về danh mục này",
"Validating...": "Đang xác thực...",
"View All": "Xem tất cả",
"Forward": "Tiếp",
"Home": "Trang chủ",
"{{count}} items_other": "{{count}} mục",
"Download completed": "Tải xuống hoàn tất",
"Download failed": "Tải xuống thất bại",
"Open Access": "Truy cập mở",
"Borrow": "Mượn",
"Buy": "Mua",
"Subscribe": "Đăng ký",
"Sample": "Mẫu",
"Download": "Tải xuống",
"Open & Read": "Mở & Đọc",
"Tags": "Thẻ",
"Tag": "Thẻ",
"First": "Đầu tiên",
"Previous": "Trước",
"Next": "Tiếp theo",
"Last": "Cuối cùng",
"Cannot Load Page": "Không thể tải trang",
"An error occurred": "Đã xảy ra lỗi",
"Online Library": "Thư viện trực tuyến",
"URL must start with http:// or https://": "URL phải bắt đầu bằng http:// hoặc https://",
"Title, Author, Tag, etc...": "Tiêu đề, Tác giả, Thẻ, v.v...",
"Query": "Truy vấn",
"Subject": "Chủ đề",
"Enter {{terms}}": "Nhập {{terms}}",
"No search results found": "Không tìm thấy kết quả tìm kiếm",
"Failed to load OPDS feed: {{status}} {{statusText}}": "Không tải được nguồn cấp OPDS: {{status}} {{statusText}}",
"Search in {{title}}": "Tìm kiếm trong {{title}}",
"Manage Storage": "Quản lý bộ nhớ",
"Failed to load files": "Không tải được tệp",
"Deleted {{count}} file(s)_other": "Đã xóa {{count}} tệp",
"Failed to delete {{count}} file(s)_other": "Không xóa được {{count}} tệp",
"Failed to delete files": "Không xóa được tệp",
"Total Files": "Tổng số tệp",
"Total Size": "Tổng dung lượng",
"Quota": "Dung lượng cho phép",
"Used": "Đã sử dụng",
"Files": "Tệp",
"Search files...": "Tìm tệp...",
"Newest First": "Mới nhất trước",
"Oldest First": "Cũ nhất trước",
"Largest First": "Lớn nhất trước",
"Smallest First": "Nhỏ nhất trước",
"Name A-Z": "Tên A-Z",
"Name Z-A": "Tên Z-A",
"{{count}} selected_other": "Đã chọn {{count}} tệp",
"Delete Selected": "Xóa các mục đã chọn",
"Created": "Đã tạo",
"No files found": "Không tìm thấy tệp",
"No files uploaded yet": "Chưa tải lên tệp nào",
"files": "tệp",
"Page {{current}} of {{total}}": "Trang {{current}} trên {{total}}",
"Are you sure to delete {{count}} selected file(s)?_other": "Bạn có chắc muốn xóa {{count}} tệp đã chọn không?",
"Cloud Storage Usage": "Sử dụng lưu trữ đám mây",
"Rename Group": "Đổi tên nhóm",
"From Directory": "Từ thư mục",
"Successfully imported {{count}} book(s)_other": "Đã nhập thành công {{count}} sách",
"Count": "Số lượng",
"Start Page": "Trang bắt đầu",
"Search in OPDS Catalog...": "Tìm kiếm trong danh mục OPDS...",
"Please log in to use advanced TTS features": "Vui lòng đăng nhập để sử dụng các tính năng TTS nâng cao",
"Word limit of 30 words exceeded.": "Đã vượt quá giới hạn 30 từ.",
"Proofread": "Hiệu đính",
"Current selection": "Vùng chọn hiện tại",
"All occurrences in this book": "Tất cả các lần xuất hiện trong sách này",
"All occurrences in your library": "Tất cả các lần xuất hiện trong thư viện của bạn",
"Selected text:": "Văn bản đã chọn:",
"Replace with:": "Thay thế bằng:",
"Enter text...": "Nhập văn bản…",
"Case sensitive:": "Phân biệt chữ hoa/thường:",
"Scope:": "Phạm vi:",
"Selection": "Vùng chọn",
"Library": "Thư viện",
"Yes": "Có",
"No": "Không",
"Proofread Replacement Rules": "Quy tắc thay thế hiệu đính",
"Selected Text Rules": "Quy tắc cho văn bản đã chọn",
"No selected text replacement rules": "Không có quy tắc thay thế cho văn bản đã chọn",
"Book Specific Rules": "Quy tắc dành riêng cho sách",
"No book-level replacement rules": "Không có quy tắc thay thế ở cấp sách",
"Disable Quick Action": "Vô hiệu hóa Hành động Nhanh",
"Enable Quick Action on Selection": "Bật Hành động Nhanh khi chọn",
"None": "Không có",
"Annotation Tools": "Công cụ chú thích",
"Enable Quick Actions": "Bật Hành động Nhanh",
"Quick Action": "Hành động Nhanh",
"Copy to Notebook": "Sao chép vào Sổ tay",
"Copy text after selection": "Sao chép văn bản sau khi chọn",
"Highlight text after selection": "Đánh dấu văn bản sau khi chọn",
"Annotate text after selection": "Chú thích văn bản sau khi chọn",
"Search text after selection": "Tìm kiếm văn bản sau khi chọn",
"Look up text in dictionary after selection": "Tra cứu văn bản trong từ điển sau khi chọn",
"Look up text in Wikipedia after selection": "Tra cứu văn bản trong Wikipedia sau khi chọn",
"Translate text after selection": "Dịch văn bản sau khi chọn",
"Read text aloud after selection": "Đọc to văn bản sau khi chọn",
"Proofread text after selection": "Hiệu đính văn bản sau khi chọn",
"{{activeCount}} active, {{pendingCount}} pending": "{{activeCount}} đang hoạt động, {{pendingCount}} đang chờ",
"{{failedCount}} failed": "{{failedCount}} thất bại",
"Waiting...": "Đang chờ...",
"Failed": "Thất bại",
"Completed": "Hoàn thành",
"Cancelled": "Đã hủy",
"Retry": "Thử lại",
"Active": "Đang hoạt động",
"Transfer Queue": "Hàng đợi truyền",
"Upload All": "Tải lên tất cả",
"Download All": "Tải xuống tất cả",
"Resume Transfers": "Tiếp tục truyền",
"Pause Transfers": "Tạm dừng truyền",
"Pending": "Đang chờ",
"No transfers": "Không có truyền",
"Retry All": "Thử lại tất cả",
"Clear Completed": "Xóa đã hoàn thành",
"Clear Failed": "Xóa thất bại",
"Upload queued: {{title}}": "Tải lên trong hàng đợi: {{title}}",
"Download queued: {{title}}": "Tải xuống trong hàng đợi: {{title}}",
"Book not found in library": "Không tìm thấy sách trong thư viện",
"Unknown error": "Lỗi không xác định",
"Please log in to continue": "Vui lòng đăng nhập để tiếp tục",
"Cloud File Transfers": "Truyền tệp đám mây",
"Show Search Results": "Hiển thị kết quả tìm kiếm",
"Search results for '{{term}}'": "Kết quả cho '{{term}}'",
"Close Search": "Đóng tìm kiếm",
"Previous Result": "Kết quả trước",
"Next Result": "Kết quả tiếp theo",
"Bookmarks": "Dấu trang",
"Annotations": "Chú thích",
"Show Results": "Hiển thị kết quả",
"Clear search": "Xóa tìm kiếm",
"Clear search history": "Xóa lịch sử tìm kiếm",
"Tap to Toggle Footer": "Nhấn để bật/tắt chân trang",
"Exported successfully": "Xuất thành công",
"Book exported successfully.": "Sách đã được xuất thành công.",
"Failed to export the book.": "Xuất sách thất bại.",
"Export Book": "Xuất sách",
"Whole word:": "Toàn bộ từ:",
"Error": "Lỗi",
"Unable to load the article. Try searching directly on {{link}}.": "Không thể tải bài viết. Hãy thử tìm kiếm trực tiếp trên {{link}}.",
"Unable to load the word. Try searching directly on {{link}}.": "Không thể tải từ. Hãy thử tìm kiếm trực tiếp trên {{link}}.",
"Date Published": "Ngày xuất bản",
"Only for TTS:": "Chỉ dành cho TTS:",
"Uploaded": "Đã tải lên",
"Downloaded": "Đã tải xuống",
"Deleted": "Đã xóa",
"Note:": "Ghi chú:",
"Time:": "Thời gian:",
"Format Options": "Tùy chọn định dạng",
"Export Date": "Ngày xuất",
"Chapter Titles": "Tiêu đề chương",
"Chapter Separator": "Dấu phân cách chương",
"Highlights": "Đánh dấu",
"Note Date": "Ngày ghi chú",
"Advanced": "Nâng cao",
"Hide": "Ẩn",
"Show": "Hiển thị",
"Use Custom Template": "Sử dụng mẫu tùy chỉnh",
"Export Template": "Mẫu xuất",
"Template Syntax:": "Cú pháp mẫu:",
"Insert value": "Chèn giá trị",
"Format date (locale)": "Định dạng ngày (địa phương)",
"Format date (custom)": "Định dạng ngày (tùy chỉnh)",
"Conditional": "Điều kiện",
"Loop": "Vòng lặp",
"Available Variables:": "Biến có sẵn:",
"Book title": "Tiêu đề sách",
"Book author": "Tác giả sách",
"Export date": "Ngày xuất",
"Array of chapters": "Danh sách chương",
"Chapter title": "Tiêu đề chương",
"Array of annotations": "Danh sách chú thích",
"Highlighted text": "Văn bản được đánh dấu",
"Annotation note": "Ghi chú chú thích",
"Date Format Tokens:": "Token định dạng ngày:",
"Year (4 digits)": "Năm (4 chữ số)",
"Month (01-12)": "Tháng (01-12)",
"Day (01-31)": "Ngày (01-31)",
"Hour (00-23)": "Giờ (00-23)",
"Minute (00-59)": "Phút (00-59)",
"Second (00-59)": "Giây (00-59)",
"Show Source": "Hiển thị nguồn",
"No content to preview": "Không có nội dung để xem trước",
"Export": "Xuất",
"Set Timeout": "Đặt thời gian chờ",
"Select Voice": "Chọn giọng nói",
"Toggle Sticky Bottom TTS Bar": "Bật/tắt thanh TTS cố định",
"Display what I'm reading on Discord": "Hiển thị sách đang đọc trên Discord",
"Show on Discord": "Hiện trên Discord",
"Instant {{action}}": "{{action}} tức thì",
"Instant {{action}} Disabled": "{{action}} tức thì đã tắt",
"Annotation": "Chú thích",
"Reset Template": "Đặt lại mẫu",
"Annotation style": "Kiểu chú thích",
"Annotation color": "Màu chú thích",
"Annotation time": "Thời gian chú thích",
"AI": "AI",
"Are you sure you want to re-index this book?": "Bạn có chắc muốn lập chỉ mục lại cuốn sách này?",
"Enable AI in Settings": "Bật AI trong Cài đặt",
"Index This Book": "Lập chỉ mục sách này",
"Enable AI search and chat for this book": "Bật tìm kiếm AI và trò chuyện cho cuốn sách này",
"Start Indexing": "Bắt đầu lập chỉ mục",
"Indexing book...": "Đang lập chỉ mục sách...",
"Preparing...": "Đang chuẩn bị...",
"Delete this conversation?": "Xóa cuộc trò chuyện này?",
"No conversations yet": "Chưa có cuộc trò chuyện nào",
"Start a new chat to ask questions about this book": "Bắt đầu cuộc trò chuyện mới để hỏi về cuốn sách này",
"Rename": "Đổi tên",
"New Chat": "Cuộc trò chuyện mới",
"Chat": "Trò chuyện",
"Please enter a model ID": "Vui lòng nhập ID mô hình",
"Model not available or invalid": "Mô hình không khả dụng hoặc không hợp lệ",
"Failed to validate model": "Xác thực mô hình thất bại",
"Couldn't connect to Ollama. Is it running?": "Không thể kết nối với Ollama. Nó có đang chạy không?",
"Invalid API key or connection failed": "Khóa API không hợp lệ hoặc kết nối thất bại",
"Connection failed": "Kết nối thất bại",
"AI Assistant": "Trợ lý AI",
"Enable AI Assistant": "Bật trợ lý AI",
"Provider": "Nhà cung cấp",
"Ollama (Local)": "Ollama (Cục bộ)",
"AI Gateway (Cloud)": "Cổng AI (Đám mây)",
"Ollama Configuration": "Cấu hình Ollama",
"Refresh Models": "Làm mới mô hình",
"AI Model": "Mô hình AI",
"No models detected": "Không phát hiện mô hình nào",
"AI Gateway Configuration": "Cấu hình cổng AI",
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Chọn từ các mô hình AI chất lượng cao, tiết kiệm. Bạn cũng có thể sử dụng mô hình riêng bằng cách chọn \"Mô hình tùy chỉnh\" bên dưới.",
"API Key": "Khóa API",
"Get Key": "Lấy khóa",
"Model": "Mô hình",
"Custom Model...": "Mô hình tùy chỉnh...",
"Custom Model ID": "ID mô hình tùy chỉnh",
"Validate": "Xác thực",
"Model available": "Mô hình khả dụng",
"Connection": "Kết nối",
"Test Connection": "Kiểm tra kết nối",
"Connected": "Đã kết nối",
"Custom Colors": "Màu tùy chỉnh",
"Color E-Ink Mode": "Chế độ E-Ink màu",
"Reading Ruler": "Thước đọc",
"Enable Reading Ruler": "Bật thước đọc",
"Lines to Highlight": "Số dòng cần làm nổi bật",
"Ruler Color": "Màu thước",
"Command Palette": "Bảng lệnh",
"Search settings and actions...": "Tìm kiếm cài đặt và hành động...",
"No results found for": "Không tìm thấy kết quả cho",
"Type to search settings and actions": "Nhập để tìm kiếm cài đặt và hành động",
"Recent": "Gần đây",
"navigate": "điều hướng",
"select": "chọn",
"close": "đóng",
"Search Settings": "Tìm kiếm cài đặt",
"Page Margins": "Lề trang",
"AI Provider": "Nhà cung cấp AI",
"Ollama URL": "URL Ollama",
"Ollama Model": "Mô hình Ollama",
"AI Gateway Model": "Mô hình AI Gateway",
"Actions": "Hành động",
"Navigation": "Điều hướng",
"Set status for {{count}} book(s)_other": "Đặt trạng thái cho {{count}} cuốn sách",
"Mark as Unread": "Đánh dấu là chưa đọc",
"Mark as Finished": "Đánh dấu là đã hoàn thành",
"Finished": "Đã hoàn thành",
"Unread": "Chưa đọc",
"Clear Status": "Xóa trạng thái",
"Status": "Trạng thái",
"Loading": "Đang tải...",
"Exit Paragraph Mode": "Thoát chế độ đoạn văn",
"Paragraph Mode": "Chế độ đoạn văn",
"Embedding Model": "Mô hình nhúng",
"{{count}} book(s) synced_other": "Đã đồng bộ {{count}} cuốn sách",
"Unable to start RSVP": "Không thể bắt đầu RSVP",
"RSVP not supported for PDF": "RSVP không được hỗ trợ cho PDF",
"Select Chapter": "Chọn chương",
"{{number}} WPM": "{{number}} WPM",
"Context": "Ngữ cảnh",
"Ready": "Sẵn sàng",
"Chapter Progress": "Tiến độ chương",
"words": "từ",
"{{time}} left": "còn lại {{time}}",
"Reading progress": "Tiến độ đọc",
"Click to seek": "Nhấp để tua",
"Skip back 15 words": "Lùi lại 15 từ",
"Back 15 words (Shift+Left)": "Lùi lại 15 từ (Shift+Trái)",
"Pause (Space)": "Tạm dừng (Khoảng trắng)",
"Play (Space)": "Phát (Khoảng trắng)",
"Skip forward 15 words": "Tiến tới 15 từ",
"Forward 15 words (Shift+Right)": "Tiến tới 15 từ (Shift+Phải)",
"Pause:": "Tạm dừng:",
"Decrease speed": "Giảm tốc độ",
"Slower (Left/Down)": "Chậm hơn (Trái/Xuống)",
"Current speed": "Tốc độ hiện tại",
"Increase speed": "Tăng tốc độ",
"Faster (Right/Up)": "Nhanh hơn (Phải/Lên)",
"Start RSVP Reading": "Bắt đầu đọc RSVP",
"Choose where to start reading": "Chọn nơi để bắt đầu đọc",
"From Chapter Start": "Từ đầu chương",
"Start reading from the beginning of the chapter": "Bắt đầu đọc lại từ đầu chương này",
"Resume": "Tiếp tục",
"Continue from where you left off": "Tiếp tục từ nơi bạn đã dừng lại",
"From Current Page": "Từ trang hiện tại",
"Start from where you are currently reading": "Bắt đầu từ nơi bạn hiện đang đọc",
"From Selection": "Từ phần đã chọn",
"Speed Reading Mode": "Chế độ đọc nhanh",
"Scroll left": "Cuộn sang trái",
"Scroll right": "Cuộn sang phải",
"Library Sync Progress": "Tiến trình đồng bộ hóa thư viện",
"Back to library": "Quay lại thư viện",
"Group by...": "Nhóm theo...",
"Export as Plain Text": "Xuất dưới dạng văn bản thuần túy",
"Export as Markdown": "Xuất dưới dạng Markdown",
"Show Page Navigation Buttons": "Nút điều hướng trang",
"Page {{number}}": "Trang {{number}}",
"highlight": "làm nổi bật",
"underline": "gạch chân",
"squiggly": "ngoằn ngoèo",
"red": "đỏ",
"violet": "tím",
"blue": "xanh lam",
"green": "xanh lá",
"yellow": "vàng",
"Select {{style}} style": "Chọn kiểu {{style}}",
"Select {{color}} color": "Chọn màu {{color}}",
"Close Book": "Đóng sách",
"Speed Reading": "Đọc nhanh",
"Close Speed Reading": "Đóng đọc nhanh",
"Authors": "Tác giả",
"Books": "Sách",
"Groups": "Nhóm",
"Back to TTS Location": "Quay lại vị trí TTS"
}
@@ -5,11 +5,9 @@
"Animation": "动画",
"Annotate": "笔记",
"Apply": "应用",
"Are you sure to delete the selected books?": "您确定要删除所选书籍吗?",
"Auto Mode": "自动主题",
"Behavior": "行为",
"Book": "书籍",
"Book Cover": "书籍封面",
"Bookmark": "书签",
"Cancel": "取消",
"Chapter": "章节",
@@ -19,7 +17,6 @@
"Confirm Deletion": "确认删除",
"Copied to notebook": "已复制到笔记本",
"Copy": "复制",
"Custom CSS": "自定义 CSS",
"Dark Mode": "深色主题",
"Default": "默认",
"Default Font": "默认字体",
@@ -27,10 +24,8 @@
"Delete": "删除",
"Delete Highlight": "删除划线",
"Dictionary": "词典",
"Disable Click-to-Flip": "禁用点击翻页",
"Download Readest": "下载 Readest",
"Edit": "编辑",
"Enter your custom CSS here...": "在此处输入您的自定义 CSS...",
"Excerpts": "摘录",
"Failed to import book(s): {{filenames}}": "导入书籍失败:{{filenames}}",
"Fast": "快",
@@ -43,17 +38,13 @@
"Global Settings": "全局设置",
"Go Back": "返回",
"Go Forward": "前进",
"Go Left": "向左",
"Go Right": "向右",
"Grass": "青草",
"Gray": "素雅",
"Gruvbox": "暖橘",
"Highlight": "划线",
"Horizontal Direction": "横排",
"Hyphenation": "断字",
"Identifier:": "识别码",
"Import Books": "导入书籍",
"Language:": "语言",
"Layout": "布局",
"Light Mode": "浅色主题",
"Loading...": "加载中...",
@@ -64,7 +55,6 @@
"Match Whole Words": "匹配整个单词",
"Maximum Number of Columns": "分栏数",
"Minimum Font Size": "最小字号",
"Misc": "杂项",
"Monospace Font": "等宽字体",
"More Info": "更多信息",
"Nord": "极光",
@@ -76,8 +66,8 @@
"Paging Animation": "翻页动画",
"Paragraph": "段落",
"Parallel Read": "并排阅读",
"Published:": "出版日期",
"Publisher:": "出版商",
"Published": "出版日期",
"Publisher": "出版商",
"Reading Progress Synced": "阅读进度已同步",
"Reload Page": "重新加载页面",
"Reveal in File Explorer": "在文件管理器中显示",
@@ -91,28 +81,25 @@
"Search...": "搜索...",
"Select Book": "选择书籍",
"Select Books": "选择书籍",
"Select Multiple Books": "选择多本书籍",
"Sepia": "旧韵",
"Serif Font": "衬线字体",
"Show Book Details": "显示书籍详情",
"Sidebar": "侧边栏",
"Sign In": "登录",
"Sign Out": "登出",
"Sign Out": "登出账户",
"Sky": "天青",
"Slow": "慢",
"Solarized": "日晖",
"Speak": "朗读",
"Subjects:": "主题",
"Subjects": "主题",
"System Fonts": "系统字体",
"TTS not supported in this device": "此设备不支持 TTS",
"Theme Color": "主题颜色",
"Theme Mode": "主题模式",
"Translate": "翻译",
"Translated Text": "译文",
"Unknown": "未知",
"Untitled": "无标题",
"Updated:": "更新日期",
"User avatar": "用户头像",
"Updated": "更新日期",
"Version {{version}}": "版本 {{version}}",
"Vertical Direction": "竖排",
"Welcome to your library. You can import your books here and read them anytime.": "书库空空如也,您可以导入您的书籍并随时阅读。",
@@ -121,26 +108,21 @@
"Your Library": "书库",
"TTS not supported for PDF": "PDF 文档暂不支持 TTS",
"Override Book Font": "覆盖书籍字体",
"Vertical Margins (px)": "垂直边距(px",
"Horizontal Margins (%)": "水平边距(%",
"Apply to All Books": "应用于所有书籍",
"Apply to This Book": "应用于此书籍",
"Unable to fetch the translation. Try again later.": "无法获取翻译,请稍后重试。",
"Update Now!": "立即更新!",
"Update": "更新",
"Check Update": "检查更新",
"Already the latest version": "已经是最新版本",
"Book Details": "书籍详情",
"From Local File": "从本地文件导入",
"TOC": "目录",
"Table of Contents": "目录",
"Book uploaded: {{title}}": "书籍已上传:{{title}}",
"Failed to upload book: {{title}}": "上传书籍失败:{{title}}",
"Book downloaded: {{title}}": "书籍已下载:{{title}}",
"Failed to download book: {{title}}": "下载书籍失败:{{title}}",
"Upload Book": "上传书籍",
"Auto Upload Books to Cloud": "自动上传书籍到云端",
"{{percentage}}% of Cloud Storage Used.": "已使用 {{percentage}}% 云存储空间",
"Storage": "存储空间",
"Book deleted: {{title}}": "书籍已删除:{{title}}",
"Failed to delete book: {{title}}": "删除书籍失败:{{title}}",
"Check Updates on Start": "启动时检查更新",
@@ -172,7 +154,7 @@
"Create a Password": "创建密码",
"Sign up": "注册",
"Signing up...": "正在注册...",
"Dont have an account? Sign up": "没有账号?注册",
"Don't have an account? Sign up": "没有账号?注册",
"Check your email for the confirmation link": "检查您的电子邮件以获取确认链接",
"Signing in ...": "正在登录...",
"Send a magic link email": "发送魔法链接邮件",
@@ -191,50 +173,24 @@
"Token": "令牌",
"Your OTP token": "您的 OTP 令牌",
"Verify token": "验证令牌",
"Sign in with Google": "使用 Google 登录",
"Sign in with Apple": "使用 Apple 登录",
"Sign in with GitHub": "使用 GitHub 登录",
"Account": "账户",
"Cloud Storage": "云存储",
"Failed to delete user. Please try again later.": "删除用户失败。请稍后重试。",
"Unlimited Offline/Online Reading": "无限离线和在线阅读",
"Unlimited Cloud Sync Devices": "无限云同步设备个数",
"Essential Text-to-Speech Voices": "基础 TTS 语音包",
"DeepL Free Access": "免费版 DeepL 翻译",
"Community Support": "社区支持",
"500 MB Cloud Sync Space": "500 MB 云同步空间",
"Includes All Free Tier Benefits": "包含所有免费版权益",
"AI Summaries": "AI 摘要",
"AI Translations": "AI 翻译",
"Priority Support": "优先支持",
"DeepL Pro Access": "专业版 DeepL 翻译",
"Expanded Text-to-Speech Voices": "更多文本转语音声音",
"2000 MB Cloud Sync Space": "2000 MB 云同步空间",
"Includes All Plus Tier Benefits": "包含所有增强版权益",
"Unlimited AI Summaries": "无限使用 AI 摘要",
"Unlimited AI Translations": "无限使用 AI 翻译",
"Unlimited DeepL Pro Access": "无限使用专业版 DeepL 翻译",
"Advanced AI Tools": "高级 AI 工具",
"Early Feature Access": "抢先体验新功能",
"10 GB Cloud Sync Space": "10 GB 云同步空间",
"Loading profile...": "加载个人资料中...",
"Features": "功能特性",
"Delete Account": "删除账户",
"Delete Your Account?": "删除您的账户?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "此操作无法撤销。您在云端的所有数据将被永久删除。",
"Delete Permanently": "永久删除",
"Free Tier": "免费版",
"Plus Tier": "增强版",
"Pro Tier": "专业版",
"RTL Direction": "从右向左",
"Maximum Column Height": "最大列高",
"Maximum Column Width": "最大列宽",
"Continuous Scroll": "连续滚动",
"Fullscreen": "全屏",
"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": "文本颜色",
@@ -260,10 +216,808 @@
"Export Annotations": "导出笔记",
"Auto Import on File Open": "打开文件时自动导入",
"LXGW WenKai GB Screen": "霞鹜文楷",
"Swap Click-to-Flip Area": "交换点击翻页区域",
"No chapters detected.": "未检测到章节",
"Failed to parse the EPUB file.": "无法解析 EPUB 文件",
"This book format is not supported.": "不支持此书籍格式",
"LXGW WenKai TC": "霞鶩文楷",
"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": "分组"
"Group": "分组",
"Always on Top": "窗口置顶",
"No Timeout": "关闭定时",
"{{value}} minute": "{{value}}分钟",
"{{value}} minutes": "{{value}}分钟",
"{{value}} hour": "{{value}}小时",
"{{value}} hours": "{{value}}小时",
"CJK Font": "中文字体",
"Clear Search": "清除搜索",
"Header & Footer": "页眉页脚",
"Apply also in Scrolled Mode": "应用到滚动模式",
"A new version of Readest is available!": "有新版本的 Readest 可更新!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} 可更新(已安装版本 {{currentVersion}})。",
"Download and install now?": "立即下载并安装?",
"Downloading {{downloaded}} of {{contentLength}}": "正在下载 {{downloaded}} / {{contentLength}}",
"Download finished": "下载完成",
"DOWNLOAD & INSTALL": "下载并安装",
"Changelog": "更新日志",
"Software Update": "软件更新",
"Title": "书名",
"Date Read": "阅读日期",
"Date Added": "添加日期",
"Format": "格式",
"Ascending": "升序",
"Descending": "降序",
"Sort by...": "排序方式...",
"Added": "添加日期",
"GuanKiapTsingKhai-T": "原俠正楷-T",
"Description": "简介",
"No description available": "暂无简介",
"List": "列表",
"Grid": "网格",
"(from 'As You Like It', Act II)": "出自《皆大欢喜》,第二幕",
"Link Color": "链接颜色",
"Volume Keys for Page Flip": "音量键翻页",
"Screen": "屏幕",
"Orientation": "屏幕方向",
"Portrait": "竖屏",
"Landscape": "横屏",
"Open Last Book on Start": "启动时打开上次阅读的书籍",
"Checking for updates...": "检查更新中...",
"Error checking for updates": "检查更新时出错",
"Details": "详情",
"File Size": "文件大小",
"Auto Detect": "自动检测",
"Next Section": "下一章",
"Previous Section": "上一章",
"Next Page": "下一页",
"Previous Page": "上一页",
"Are you sure to delete {{count}} selected book(s)?_other": "您确定要删除 {{count}} 本选中的书籍吗?",
"Are you sure to delete the selected book?": "您确定要删除选中的书籍吗?",
"Deselect": "取消选择",
"Select All": "全选",
"No translation available.": "暂无可用的翻译",
"Translated by {{provider}}.": "由 {{provider}} 提供翻译",
"DeepL": "DeepL",
"Google Translate": "Google Translate",
"Azure Translator": "Azure Translator",
"Invert Image In Dark Mode": "深色主题下图片反色",
"Help improve Readest": "帮助改进 Readest",
"Sharing anonymized statistics": "分享匿名统计数据",
"Interface Language": "界面语言",
"Translation": "翻译",
"Enable Translation": "启用翻译",
"Translation Service": "翻译服务",
"Translate To": "翻译到",
"Disable Translation": "禁用翻译",
"Scroll": "滚动",
"Overlap Pixels": "重叠像素",
"System Language": "系统语言",
"Security": "安全",
"Allow JavaScript": "允许 JavaScript",
"Enable only if you trust the file.": "建议仅在您信任该文件时启用",
"Sort TOC by Page": "按页码排序目录",
"Search in {{count}} Book(s)..._other": "在 {{count}} 本书籍中搜索...",
"No notes match your search": "未找到匹配的笔记",
"Search notes and excerpts...": "搜索笔记...",
"Sign in to Sync": "登录后同步",
"Synced at {{time}}": "同步于:{{time}}",
"Never synced": "从未同步",
"Show Remaining Time": "显示剩余时间",
"{{time}} min left in chapter": "本章剩余 {{time}} 分钟",
"Override Book Color": "覆盖书籍颜色",
"Login Required": "需登录",
"Quota Exceeded": "额度不足",
"{{percentage}}% of Daily Translation Characters Used.": "已使用 {{percentage}}% 的每日翻译字符数",
"Translation Characters": "翻译字数",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}} 种语音",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "出了点问题。请不要担心,我们的团队已经收到通知并正在修复中。",
"Error Details:": "错误详情:",
"Try Again": "重试",
"Need help?": "需要帮助吗?",
"Contact Support": "联系客服",
"Code Highlighting": "代码高亮",
"Enable Highlighting": "启用高亮",
"Code Language": "代码语言",
"Top Margin (px)": "上边距",
"Bottom Margin (px)": "下边距",
"Right Margin (px)": "右边距",
"Left Margin (px)": "左边距",
"Column Gap (%)": "列间距",
"Always Show Status Bar": "始终显示状态栏",
"Custom Content CSS": "自定义内容 CSS",
"Enter CSS for book content styling...": "输入书籍内容样式的CSS…",
"Custom Reader UI CSS": "自定义界面 CSS",
"Enter CSS for reader interface styling...": "输入阅读器界面样式的CSS…",
"Crop": "裁剪",
"Book Covers": "书籍封面",
"Fit": "适应",
"Reset {{settings}}": "重置{{settings}}",
"Reset Settings": "重置设置",
"{{count}} pages left in chapter_other": "本章剩余 {{count}} 页",
"Show Remaining Pages": "显示剩余页数",
"Source Han Serif CN": "思源宋体",
"Huiwen-MinchoGBK": "汇文明朝体",
"KingHwa_OldSong": "京华老宋体",
"Manage Subscription": "管理订阅",
"Coming Soon": "即将上线",
"Upgrade to {{plan}}": "升级到 {{plan}}",
"Upgrade to Plus or Pro": "升级到 Plus 或 Pro",
"Current Plan": "当前套餐",
"Plan Limits": "套餐限制",
"Processing your payment...": "正在处理付款...",
"Please wait while we confirm your subscription.": "请稍候,我们正在确认您的订阅。",
"Payment Processing": "付款处理中",
"Your payment is being processed. This usually takes a few moments.": "您的付款正在处理中,通常需要几秒钟。",
"Payment Failed": "付款失败",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "我们无法处理您的订阅。请重试,或如问题持续请联系支持。",
"Back to Profile": "返回个人资料",
"Subscription Successful!": "订阅成功!",
"Thank you for your subscription! Your payment has been processed successfully.": "感谢您的订阅!您的付款已成功处理。",
"Email:": "邮箱:",
"Plan:": "套餐:",
"Amount:": "金额:",
"Go to Library": "前往书库",
"Need help? Contact our support team at support@readest.com": "需要帮助?请联系支持团队:support@readest.com",
"Free Plan": "免费套餐",
"month": "月",
"AI Translations (per day)": "AI 翻译(每日)",
"Plus Plan": "Plus 套餐",
"Includes All Free Plan Benefits": "包含所有免费套餐功能",
"Pro Plan": "Pro 套餐",
"More AI Translations": "更多 AI 翻译",
"Complete Your Subscription": "完成您的订阅",
"{{percentage}}% of Cloud Sync Space Used.": "已使用 {{percentage}}% 的云同步空间。",
"Cloud Sync Storage": "云同步空间",
"Disable": "禁用",
"Enable": "启用",
"Upgrade to Readest Premium": "升级到 Readest Premium",
"Show Source Text": "显示原文",
"Cross-Platform Sync": "跨平台同步",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "在所有设备间无缝同步您的书库、进度、标注和笔记——再也不会丢失阅读位置。",
"Customizable Reading": "个性化阅读",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "通过可调节的字体、布局、主题和高级显示设置个性化每个细节,获得完美阅读体验。",
"AI Read Aloud": "AI 朗读",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "享受解放双手的阅读体验,使用自然流畅的 AI 语音让书籍栩栩如生。",
"AI Translations": "AI 翻译",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "借助 Google、Azure 或 DeepL 的强大功能即时翻译任何语言的内容。",
"Connect with fellow readers and get help fast in our friendly community channels.": "与其他读者交流,在我们友好的社区频道中快速获得帮助。",
"Unlimited AI Read Aloud Hours": "无限 AI 朗读时长",
"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 访问权限",
"Enjoy faster responses and dedicated assistance whenever you need help.": "享受更快响应和专属帮助,随时获得支持。",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "已达每日翻译配额。升级套餐以继续使用 AI 翻译。",
"Includes All Plus Plan Benefits": "包含所有 Plus 套餐功能",
"Early Feature Access": "抢先体验新功能",
"Be the first to explore new features, updates, and innovations before anyone else.": "抢先体验最新功能、更新与创新成果。",
"Advanced AI Tools": "高级 AI 工具",
"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万字。",
"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}}",
"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 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": "本章剩余{{number}}页",
"Device": "设备",
"E-Ink Mode": "E-Ink 模式",
"Highlight Colors": "高亮颜色",
"Auto Screen Brightness": "自动屏幕亮度",
"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.": "Web 版不支持添加局域网地址。",
"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": "点击切换页脚",
"Exported successfully": "导出成功",
"Book exported successfully.": "书籍导出成功。",
"Failed to export the book.": "书籍导出失败。",
"Export Book": "导出书籍",
"Whole word:": "全词匹配:",
"Only for TTS:": "仅用于TTS",
"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": "出版日期",
"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": "选择章节",
"{{number}} WPM": "{{number}} WPM",
"Context": "上下文",
"Ready": "准备就绪",
"Chapter Progress": "章节进度",
"words": "词",
"{{time}} left": "剩余 {{time}}",
"Reading progress": "阅读进度",
"Click to seek": "点击跳转",
"Skip back 15 words": "回退 15 词",
"Back 15 words (Shift+Left)": "回退 15 词 (Shift+Left)",
"Pause (Space)": "暂停 (空格)",
"Play (Space)": "播放 (空格)",
"Skip forward 15 words": "前进 15 词",
"Forward 15 words (Shift+Right)": "前进 15 词 (Shift+Right)",
"Pause:": "暂停:",
"Decrease speed": "减速",
"Slower (Left/Down)": "较慢 (左/下)",
"Current speed": "当前速度",
"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": "回到朗读位置"
}
@@ -5,11 +5,9 @@
"Animation": "動畫",
"Annotate": "筆記",
"Apply": "應用",
"Are you sure to delete the selected books?": "您確定要刪除所選書籍嗎?",
"Auto Mode": "自動主題",
"Behavior": "行為",
"Book": "書籍",
"Book Cover": "書籍封面",
"Bookmark": "書籤",
"Cancel": "取消",
"Chapter": "章節",
@@ -19,7 +17,6 @@
"Confirm Deletion": "確認刪除",
"Copied to notebook": "已複製到筆記本",
"Copy": "複製",
"Custom CSS": "自定義 CSS",
"Dark Mode": "深色主題",
"Default": "預設",
"Default Font": "預設字體",
@@ -27,10 +24,8 @@
"Delete": "刪除",
"Delete Highlight": "刪除劃線",
"Dictionary": "詞典",
"Disable Click-to-Flip": "禁用點擊翻頁",
"Download Readest": "下載 Readest",
"Edit": "編輯",
"Enter your custom CSS here...": "在此處輸入您的自定義 CSS...",
"Excerpts": "摘錄",
"Failed to import book(s): {{filenames}}": "導入書籍失敗:{{filenames}}",
"Fast": "快",
@@ -43,17 +38,13 @@
"Global Settings": "全局設置",
"Go Back": "返回",
"Go Forward": "前進",
"Go Left": "向左",
"Go Right": "向右",
"Grass": "青草",
"Gray": "素雅",
"Gruvbox": "暖橘",
"Highlight": "劃線",
"Horizontal Direction": "橫排",
"Hyphenation": "斷字",
"Identifier:": "識別碼",
"Import Books": "導入書籍",
"Language:": "語言",
"Layout": "版面",
"Light Mode": "淺色主題",
"Loading...": "載入中...",
@@ -64,7 +55,6 @@
"Match Whole Words": "匹配整個單詞",
"Maximum Number of Columns": "分欄數",
"Minimum Font Size": "最小字號",
"Misc": "雜項",
"Monospace Font": "等寬字體",
"More Info": "更多信息",
"Nord": "極光",
@@ -76,8 +66,8 @@
"Paging Animation": "翻頁動畫",
"Paragraph": "段落",
"Parallel Read": "並排閱讀",
"Published:": "出版日期",
"Publisher:": "出版商",
"Published": "出版日期",
"Publisher": "出版商",
"Reading Progress Synced": "閱讀進度已同步",
"Reload Page": "重新載入頁面",
"Reveal in File Explorer": "在檔案管理器中顯示",
@@ -91,7 +81,6 @@
"Search...": "搜索...",
"Select Book": "選擇書籍",
"Select Books": "選擇書籍",
"Select Multiple Books": "選擇多本書籍",
"Sepia": "舊韻",
"Serif Font": "襯線字體",
"Show Book Details": "顯示書籍詳情",
@@ -102,17 +91,15 @@
"Slow": "慢",
"Solarized": "日暉",
"Speak": "朗讀",
"Subjects:": "主題",
"Subjects": "主題",
"System Fonts": "系統字體",
"TTS not supported in this device": "此設備不支持 TTS",
"Theme Color": "主題顏色",
"Theme Mode": "主題模式",
"Translate": "翻譯",
"Translated Text": "譯文",
"Unknown": "未知",
"Untitled": "無標題",
"Updated:": "更新日期",
"User avatar": "用戶頭像",
"Updated": "更新日期",
"Version {{version}}": "版本 {{version}}",
"Vertical Direction": "豎排",
"Welcome to your library. You can import your books here and read them anytime.": "書庫空空如也,您可以導入您的書籍並隨時閱讀。",
@@ -121,26 +108,21 @@
"Your Library": "書庫",
"TTS not supported for PDF": "PDF 文檔暫不支持 TTS",
"Override Book Font": "覆蓋書籍字體",
"Vertical Margins (px)": "垂直邊距(px",
"Horizontal Margins (%)": "水平邊距(%",
"Apply to All Books": "應用於所有書籍",
"Apply to This Book": "應用於此書籍",
"Unable to fetch the translation. Try again later.": "無法獲取翻譯,請稍後再試。",
"Update Now!": "立即更新!",
"Update": "更新",
"Check Update": "檢查更新",
"Already the latest version": "已經是最新版本",
"Book Details": "書籍詳情",
"From Local File": "從本地文件導入",
"TOC": "目錄",
"Table of Contents": "目錄",
"Book uploaded: {{title}}": "書籍已上傳:{{title}}",
"Failed to upload book: {{title}}": "書籍上傳失敗:{{title}}",
"Book downloaded: {{title}}": "書籍已下載:{{title}}",
"Failed to download book: {{title}}": "書籍下載失敗:{{title}}",
"Upload Book": "上傳書籍",
"Auto Upload Books to Cloud": "自動上傳書籍到雲端",
"{{percentage}}% of Cloud Storage Used.": "已使用 {{percentage}}% 雲存儲空間",
"Storage": "存儲空間",
"Book deleted: {{title}}": "書籍已刪除:{{title}}",
"Failed to delete book: {{title}}": "書籍刪除失敗:{{title}}",
"Check Updates on Start": "啟動時檢查更新",
@@ -172,7 +154,7 @@
"Create a Password": "創建密碼",
"Sign up": "註冊",
"Signing up...": "正在註冊...",
"Dont have an account? Sign up": "沒有帳號?註冊",
"Don't have an account? Sign up": "沒有帳號?註冊",
"Check your email for the confirmation link": "檢查您的電子郵件以獲取確認連結",
"Signing in ...": "正在登入...",
"Send a magic link email": "發送魔法連結郵件",
@@ -191,41 +173,15 @@
"Token": "令牌",
"Your OTP token": "您的 OTP 令牌",
"Verify token": "驗證令牌",
"Sign in with Google": "使用 Google 登入",
"Sign in with Apple": "使用 Apple 登入",
"Sign in with GitHub": "使用 GitHub 登入",
"Account": "帳戶",
"Cloud Storage": "雲端儲存空間",
"Failed to delete user. Please try again later.": "刪除使用者失敗。請稍後再試。",
"Unlimited Offline/Online Reading": "無限離線/線上閱讀",
"Unlimited Cloud Sync Devices": "無限雲端同步裝置",
"Essential Text-to-Speech Voices": "基本文字轉語音聲音",
"DeepL Free Access": "DeepL免費存取",
"Community Support": "社群支援",
"500 MB Cloud Sync Space": "500 MB雲端同步空間",
"Includes All Free Tier Benefits": "包含所有免費方案權益",
"AI Summaries": "AI摘要",
"AI Translations": "AI翻譯",
"Priority Support": "優先支援",
"DeepL Pro Access": "DeepL專業版存取",
"Expanded Text-to-Speech Voices": "擴展文字轉語音聲音",
"2000 MB Cloud Sync Space": "2000 MB雲端同步空間",
"Includes All Plus Tier Benefits": "包含所有Plus方案權益",
"Unlimited AI Summaries": "無限AI摘要",
"Unlimited AI Translations": "無限AI翻譯",
"Unlimited DeepL Pro Access": "無限DeepL專業版存取",
"Advanced AI Tools": "進階AI工具",
"Early Feature Access": "搶先體驗新功能",
"10 GB Cloud Sync Space": "10 GB雲端同步空間",
"Loading profile...": "載入個人資料中...",
"Features": "功能",
"Delete Account": "刪除帳戶",
"Delete Your Account?": "刪除您的帳戶?",
"This action cannot be undone. All your data in the cloud will be permanently deleted.": "此操作無法撤銷。您在雲端的所有資料將被永久刪除。",
"Delete Permanently": "永久刪除",
"Free Tier": "免費方案",
"Plus Tier": "Plus方案",
"Pro Tier": "專業方案",
"RTL Direction": "從右向左",
"Maximum Column Height": "最大列高",
"Maximum Column Width": "最大列寬",
@@ -234,7 +190,7 @@
"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——威廉·莎士比亞",
"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——威廉·莎士比亞",
"Custom Theme": "自定義主題",
"Theme Name": "主題名稱",
"Text Color": "文字顏色",
@@ -259,11 +215,809 @@
"Copied to clipboard": "已複製到剪貼板",
"Export Annotations": "匯出筆記",
"Auto Import on File Open": "打開文件時自動導入",
"LXGW WenKai GB Screen": "霞鶩文楷",
"Swap Click-to-Flip Area": "交換點擊翻頁區域",
"No chapters detected.": "未檢測到章節",
"Failed to parse the EPUB file.": "無法解析 EPUB 文件",
"This book format is not supported.": "不支援此書籍格式",
"LXGW WenKai GB Screen": "霞鶩文楷 SC",
"LXGW WenKai TC": "霞鶩文楷 TC",
"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": "分組"
"Group": "分組",
"Always on Top": "視窗置頂",
"No Timeout": "關閉定時",
"{{value}} minute": "{{value}}分鐘",
"{{value}} minutes": "{{value}}分鐘",
"{{value}} hour": "{{value}}小時",
"{{value}} hours": "{{value}}小時",
"CJK Font": "中文字體",
"Clear Search": "清除搜索",
"Header & Footer": "頁眉頁腳",
"Apply also in Scrolled Mode": "滾動模式同樣適用",
"A new version of Readest is available!": "有新版本的 Readest 可更新!",
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} 可更新(已安裝版本 {{currentVersion}})。",
"Download and install now?": "立即下載並安裝?",
"Downloading {{downloaded}} of {{contentLength}}": "正在下載 {{downloaded}} / {{contentLength}}",
"Download finished": "下載完成",
"DOWNLOAD & INSTALL": "下載並安裝",
"Changelog": "更新日誌:",
"Software Update": "軟體更新",
"Title": "書名",
"Date Read": "閱讀日期",
"Date Added": "添加日期",
"Format": "格式",
"Ascending": "升序",
"Descending": "降序",
"Sort by...": "排序方式...",
"Added": "添加日期",
"GuanKiapTsingKhai-T": "原俠正楷-T",
"Description": "簡介",
"No description available": "暫無簡介",
"List": "列表",
"Grid": "網格",
"(from 'As You Like It', Act II)": "(出自《皆大歡喜》,第二幕)",
"Link Color": "連結顏色",
"Volume Keys for Page Flip": "音量鍵翻頁",
"Screen": "螢幕",
"Orientation": "螢幕方向",
"Portrait": "豎屏",
"Landscape": "橫屏",
"Open Last Book on Start": "啟動時打開上次閱讀的書籍",
"Checking for updates...": "檢查更新中...",
"Error checking for updates": "檢查更新時出錯",
"Details": "詳情",
"File Size": "檔案大小",
"Auto Detect": "自動檢測",
"Next Section": "下一章",
"Previous Section": "上一章",
"Next Page": "下一頁",
"Previous Page": "上一頁",
"Are you sure to delete {{count}} selected book(s)?_other": "確定要刪除已選擇的 {{count}} 本書嗎?",
"Are you sure to delete the selected book?": "確定要刪除已選擇的書籍嗎?",
"Deselect": "取消選取",
"Select All": "全選",
"No translation available.": "暫無翻譯",
"Translated by {{provider}}.": "由 {{provider}} 提供翻譯",
"DeepL": "DeepL",
"Google Translate": "Google Translate",
"Azure Translator": "Azure Translator",
"Invert Image In Dark Mode": "深色主題下圖片反相",
"Help improve Readest": "幫助改進 Readest",
"Sharing anonymized statistics": "分享匿名統計數據",
"Interface Language": "介面語言",
"Translation": "翻譯",
"Enable Translation": "啟用翻譯",
"Translation Service": "翻譯服務",
"Translate To": "翻譯至",
"Disable Translation": "停用翻譯",
"Scroll": "滾動",
"Overlap Pixels": "重疊像素",
"System Language": "系統語言",
"Security": "安全",
"Allow JavaScript": "允許 JavaScript",
"Enable only if you trust the file.": "建議僅在您信任該檔案時啟用",
"Sort TOC by Page": "依頁碼排序目錄",
"Search in {{count}} Book(s)..._other": "在 {{count}} 本書中搜索...",
"No notes match your search": "找不到符合的筆記",
"Search notes and excerpts...": "搜尋筆記...",
"Sign in to Sync": "登入以同步",
"Synced at {{time}}": "同步於:{{time}}",
"Never synced": "從未同步",
"Show Remaining Time": "顯示剩餘時間",
"{{time}} min left in chapter": "本章剩餘 {{time}} 分鐘",
"Override Book Color": "覆蓋書籍顏色",
"Login Required": "需登入",
"Quota Exceeded": "額度不足",
"{{percentage}}% of Daily Translation Characters Used.": "已使用 {{percentage}}% 的每日翻譯字數",
"Translation Characters": "翻譯字數",
"{{engine}}: {{count}} voices_other": "{{engine}}: {{count}} 種語音",
"Something went wrong. Don't worry, our team has been notified and we're working on a fix.": "出了點問題。別擔心,我們的團隊已經收到通知,正在努力修復。",
"Error Details:": "錯誤詳情:",
"Try Again": "再試一次",
"Need help?": "需要幫助嗎?",
"Contact Support": "聯繫支援",
"Code Highlighting": "程式碼高亮",
"Enable Highlighting": "啟用高亮",
"Code Language": "程式語言",
"Top Margin (px)": "上邊距",
"Bottom Margin (px)": "下邊距",
"Right Margin (px)": "右邊距",
"Left Margin (px)": "左邊距",
"Column Gap (%)": "欄間距",
"Always Show Status Bar": "始終顯示狀態欄",
"Custom Content CSS": "自訂內容 CSS",
"Enter CSS for book content styling...": "輸入書籍內容樣式的CSS…",
"Custom Reader UI CSS": "自訂介面 CSS",
"Enter CSS for reader interface styling...": "輸入閱讀器介面樣式的CSS…",
"Crop": "裁剪",
"Book Covers": "書籍封面",
"Fit": "適應",
"Reset {{settings}}": "重置{{settings}}",
"Reset Settings": "重置設置",
"{{count}} pages left in chapter_other": "本章剩餘 {{count}} 頁",
"Show Remaining Pages": "顯示剩餘頁數",
"Source Han Serif CN": "思源宋體",
"Huiwen-MinchoGBK": "匯文明朝體",
"KingHwa_OldSong": "京華老宋體",
"Manage Subscription": "管理訂閱",
"Coming Soon": "即將推出",
"Upgrade to {{plan}}": "升級到 {{plan}}",
"Upgrade to Plus or Pro": "升級到 Plus 或 Pro",
"Current Plan": "當前方案",
"Plan Limits": "方案限制",
"Processing your payment...": "正在處理付款...",
"Please wait while we confirm your subscription.": "請稍候,我們正在確認您的訂閱。",
"Payment Processing": "付款處理中",
"Your payment is being processed. This usually takes a few moments.": "您的付款正在處理中,通常需要幾秒鐘。",
"Payment Failed": "付款失敗",
"We couldn't process your subscription. Please try again or contact support if the issue persists.": "我們無法處理您的訂閱。請重試,或若問題持續,請聯絡客服。",
"Back to Profile": "返回個人資料",
"Subscription Successful!": "訂閱成功!",
"Thank you for your subscription! Your payment has been processed successfully.": "感謝您的訂閱!您的付款已成功完成。",
"Email:": "電子郵件:",
"Plan:": "方案:",
"Amount:": "金額:",
"Go to Library": "前往書庫",
"Need help? Contact our support team at support@readest.com": "需要協助?請聯絡支援團隊:support@readest.com",
"Free Plan": "免費方案",
"month": "月",
"AI Translations (per day)": "AI 翻譯(每日)",
"Plus Plan": "Plus 方案",
"Includes All Free Plan Benefits": "包含所有免費方案功能",
"Pro Plan": "Pro 方案",
"More AI Translations": "更多 AI 翻譯",
"Complete Your Subscription": "完成您的訂閱",
"{{percentage}}% of Cloud Sync Space Used.": "已使用 {{percentage}}% 的雲同步空間。",
"Cloud Sync Storage": "雲同步空間",
"Disable": "禁用",
"Enable": "啟用",
"Upgrade to Readest Premium": "升級到 Readest Premium",
"Show Source Text": "顯示原文",
"Cross-Platform Sync": "跨平台同步",
"Seamlessly sync your library, progress, highlights, and notes across all your devices—never lose your place again.": "在所有裝置間無縫同步您的書庫、閱讀進度、標註和筆記——再也不會遺失閱讀位置。",
"Customizable Reading": "個人化閱讀",
"Personalize every detail with adjustable fonts, layouts, themes, and advanced display settings for the perfect reading experience.": "透過可調節的字體、版面配置、主題和進階顯示設定個人化每個細節,獲得完美閱讀體驗。",
"AI Read Aloud": "AI 朗讀",
"Enjoy hands-free reading with natural-sounding AI voices that bring your books to life.": "享受免手持的閱讀體驗,透過自然流暢的 AI 聲音讓書籍栩栩如生。",
"AI Translations": "AI 翻譯",
"Translate any text instantly with the power of Google, Azure, or DeepL—understand content in any language.": "借助 Google、Azure 或 DeepL 的強大功能即時翻譯任何文字——理解任何語言的內容。",
"Connect with fellow readers and get help fast in our friendly community channels.": "與其他讀者交流,在我們友善的社群頻道中快速獲得幫助。",
"Unlimited AI Read Aloud Hours": "無限 AI 朗讀時長",
"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 存取權限",
"Enjoy faster responses and dedicated assistance whenever you need help.": "享受更快回應和專屬幫助,隨時獲得所需支援。",
"Daily translation quota reached. Upgrade your plan to continue using AI translations.": "已達每日翻譯配額。升級方案以繼續使用 AI 翻譯。",
"Includes All Plus Plan Benefits": "包含所有 Plus 方案優惠",
"Early Feature Access": "搶先體驗新功能",
"Be the first to explore new features, updates, and innovations before anyone else.": "搶先體驗最新功能、更新與創新成果。",
"Advanced AI Tools": "進階 AI 工具",
"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萬字元。",
"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}}",
"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 圖書",
"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 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": "本章剩餘{{number}}頁",
"Device": "設備",
"E-Ink Mode": "E-Ink 模式",
"Highlight Colors": "高亮顏色",
"Auto Screen Brightness": "自動螢幕亮度",
"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.": "網頁版不支援新增區域網路位址。",
"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": "點擊切換頁尾",
"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": "選擇章節",
"{{number}} WPM": "{{number}} WPM",
"Context": "上下文",
"Ready": "準備就緒",
"Chapter Progress": "章節進度",
"words": "詞",
"{{time}} left": "剩餘 {{time}}",
"Reading progress": "閱讀進度",
"Click to seek": "點擊跳轉",
"Skip back 15 words": "回退 15 詞",
"Back 15 words (Shift+Left)": "回退 15 詞 (Shift+Left)",
"Pause (Space)": "暫停 (空格)",
"Play (Space)": "播放 (空格)",
"Skip forward 15 words": "前進 15 詞",
"Forward 15 words (Shift+Right)": "前進 15 詞 (Shift+Right)",
"Pause:": "暫停:",
"Decrease speed": "減速",
"Slower (Left/Down)": "較慢 (左/下)",
"Current speed": "當前速度",
"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": "回到朗讀位置"
}
+672
View File
@@ -1,5 +1,677 @@
{
"releases": {
"0.9.99": {
"date": "2026-02-07",
"notes": [
"Reading: Added a reading ruler (line highlight) to help guide your eyes while reading",
"Reading: Added paragraph-by-paragraph reading mode for more focused navigation",
"Reading: Added a speed reading mode to support faster reading workflows",
"Reading: Added support for gamepad input to turn pages",
"Accessibility: Improved TalkBack support in dropdown menus for smoother navigation",
"Accessibility: Page navigation buttons are now always visible to screen readers",
"Accessibility: Reading progress is now updated correctly when navigating with screen readers",
"Annotations: Expanded highlight customization with more color options",
"Annotations: Added an option to export annotations as plain text",
"Library: Added grouping by author and series for better library organization",
"Library: Added support of marking books as finished",
"Search: Added fuzzy search to quickly find settings even with partial keywords",
"Table of Contents: Added page numbers for nested TOC entries",
"Text-to-Speech: Added navigation controls to return to the current reading position",
"Linux: Added an in-app updater for AppImage builds",
"E-ink: Improved color support for color E-ink devices to display richer highlights"
]
},
"0.9.98": {
"date": "2026-01-21",
"notes": [
"Bookshelf: Added the ability to export original book files directly from the book details dialog",
"Bookshelf: Added a new sorting option to organize books by publish date",
"Bookshelf: Improved performance for large library with faster and more stable imports",
"OPDS: Improved download reliability by correctly detecting filenames for PDF and CBZ files",
"Proofreading: Added support for whole-word replacement to make text corrections more precise",
"Notes: Added the ability to export notes using a customizable template",
"PDF: Added support for panning within PDF documents for easier navigation",
"PDF: Improved performance by pre-rendering the next page for smoother page transitions",
"Text-to-Speech: Added support for word replacement to improve pronunciation during playback",
"Text-to-Speech: Fixed an issue where playback speed settings were not applied correctly on Linux",
"E-ink: Improved reading stability by preventing unwanted scrolling when animations are disabled or on e-ink devices",
"Discord: Added Discord Rich Presence to display your current reading status on Desktop platforms",
"Android: Fixed an issue that could cause occasional crashes during app startup",
"Fonts: Improved web font loading for faster and more stable text rendering"
]
},
"0.9.97": {
"date": "2026-01-10",
"notes": [
"Annotations: Added annotation bubble icons directly on text with instant note popups",
"Annotations: Enabled quick highlighting when selecting text",
"Annotations: Added the ability to edit the text range of existing highlights",
"Annotations: Added an annotation navigation bar for easier browsing",
"OPDS: Fixed an issue where CBZ files could not be downloaded from OPDS catalogs",
"OPDS: Improved compatibility with Komga OPDS servers",
"OPDS: Added support for OPDS servers using self-signed SSL certificates",
"PDF: Fixed an issue where some PDF files failed to open",
"E-ink: Optimized colors and layout for improved e-ink device readability",
"Search: Added search term history for quicker repeated searches",
"Text-to-Speech: Reduced excessive pauses between sentences for smoother playback",
"File Transfer: Introduced a background transfer queue for uploading and downloading books",
"Proofreading: Added a proofread tool that can replace text directly within books"
]
},
"0.9.96": {
"date": "2025-12-19",
"notes": [
"TTS: Resolved an issue where Edge TTS was blocked in certain regions",
"OPDS: Improved compatibility with older versions of Calibre Web",
"OPDS: Added an instant search bar for faster browsing in OPDS catalogs",
"OPDS: Added a curated book catalog from Standard Ebooks",
"Bookshelf: Added a “Group Books” action to the context menu",
"Comics: Fixed layout issues to improve comic book reading",
"Layout: Footnote popups now adapt correctly to different screen sizes",
"Layout: Fixed an issue where the maximum inline width was not applied to EPUBs",
"Sync: Improved file downloading by correctly handling special characters in filenames",
"UI: Added an option to temporarily dismiss the reading progress bar",
"Settings: Screen brightness adjustments now apply only to the reader view",
"iOS: You can now open files directly in Readest from the Files app",
"macOS: Added a global menu option to open files with Readest"
]
},
"0.9.95": {
"date": "2025-12-08",
"notes": [
"OPDS: You can now search, browse, and download ebooks directly from OPDS catalogs",
"OPDS: Improved compatibility with Calibre Web for reliable downloads",
"OPDS: Fixed an issue where book covers from self-hosted Calibre OPDS servers did not display correctly",
"Cloud Storage: You can view and delete files stored in your cloud storage directly from the app",
"Bookshelf: Added support for importing books from a folder recursively",
"Bookshelf: You can now rename your bookshelf groups",
"EPUB: Added support for SVG covers from Standard Ebooks",
"Annotations: Keyboard shortcuts no longer copy selected text into the notebook",
"Footnotes: Footnote popups now scale properly on small screens",
"Touch/Styli: Removed the context menu for smoother interaction on touch and stylus devices",
"Layout: Devices with unfoldable screens now automatically switch to a two-column layout",
"PDF: Improved zoomed-in navigation and hand-tool behavior for smoother page navigation",
"Android: Fixed highlighting of the current sentence when using native Android text-to-speech",
"Android: Back button handling now works correctly on Android 15 and above",
"Android: You can now open files shared from other apps"
]
},
"0.9.94": {
"date": "2025-12-02",
"notes": [
"OPDS: You can now browse and download ebooks directly from OPDS catalogs",
"PDF: Added a hand-tool mode that makes navigating PDF pages easier",
"Covers: You can now choose a folder to save the latest book cover image",
"CJK: Added one-tap conversion between Simplified and Traditional Chinese",
"Shortcuts: Use Ctrl + mouse wheel to quickly zoom in or out",
"Library: Added a new option to adjust cover sizes in grid view",
"Windows: Added Ebook thumbnails with book covers in Windows Explorer",
"TTS: Fixed an issue where the page would scroll when showing the annotator",
"Annotations: Resolved layout shifts when selecting text in paginated mode on Android",
"Files: Improved backup handling to prevent file corruption",
"Layout: Fixed text clipping caused by negative indents",
"E-ink: Improved sidebar and notebook background colors for e-ink devices",
"Android: The Back button now works properly in menus, dialogs, and alerts",
"iOS: Fixed occasional failures when opening books on older iOS versions (16.4 and below)"
]
},
"0.9.93": {
"date": "2025-11-20",
"notes": [
"Sync: Improved reliability for new accounts so your books sync correctly from the start",
"Library: Fixed an occasional issue where returning to the library could get stuck",
"Layout: Improved image display in paginated mode so images won't exceed the available height",
"TXT: Improved performance and stability when opening and parsing TXT files",
"Fonts: Fixed an issue where monospace fonts were not applied correctly in code blocks"
]
},
"0.9.92": {
"date": "2025-11-18",
"notes": [
"Bookshelf: Added support for nested groups to organize your books more flexibly",
"Sync: Improved reliability by automatically retrying failed book syncs",
"Sync: Improved token refresh so login sessions stay active longer on KOReader",
"E-Ink: Enhanced readability on the library page for E-Ink devices",
"UI: Storage capacity is now displayed with precise values in the user profile",
"Reader: You can now import files directly into the currently selected book group",
"Account: You can now update the email address linked to your Readest account",
"Footnotes: Added compatibility for more footnote formats"
]
},
"0.9.91": {
"date": "2025-10-29",
"notes": [
"TTS: Fixed an issue where system voices were not working on Android",
"TTS: Added options to customize the highlight style during read-aloud",
"E-Ink: Disabled all shadows to improve display clarity",
"E-Ink: Added an option to save the last book cover on Android",
"Android: Fixed a crash that occurred when toggling 'Allow Script'",
"Android: Adjusted launcher icon size for better compatibility across devices"
]
},
"0.9.90": {
"date": "2025-10-28",
"notes": [
"Sync: Faster library syncing and support for in-app one-time purchases of extra cloud storage",
"TTS: You can now choose the target language for read-aloud on translated books",
"Reader: New keyboard shortcuts make it easier to move between sections",
"Reader: Smoother scrolling for a more comfortable reading experience",
"Reader: Footnotes in definition lists are now fully supported",
"Reader: Improved search accuracy and display of search results",
"Reader: Clearer error messages when importing books",
"Reader: Improved safety when loading book content",
"Settings: You can now choose your own highlight colors",
"Settings: Added option to adjust screen brightness automatically",
"E-Ink: Better readability and clearer progress display with underlined links",
"Android: You can now store app data on an external SD card",
"iOS: Restores your last reading page if the app was closed in the background",
"Localization: Added Persian (Farsi) language support"
]
},
"0.9.88": {
"date": "2025-10-18",
"notes": [
"TTS: Fixed issue where the read-aloud indicator disappeared too quickly",
"Layout: Overriding book layout no longer affects explicitly set text alignment",
"Reader: Added localized number display for reading progress in vertical layout",
"Reader: Enhanced swipe responsiveness for smoother page transitions",
"Settings: Added an option to disable animations when using E-Ink mode"
]
},
"0.9.87": {
"date": "2025-10-16",
"notes": [
"Reader: Improved chapter detection with better chapter title recognition",
"Reader: Enhanced compatibility for parsing more footnote formats",
"Theme: Fixed auto theme switching in new reader windows",
"TTS: Improved scrolling accuracy to highlighted text during read-aloud",
"TTS: Fixed crash issues on certain Android systems"
]
},
"0.9.86": {
"date": "2025-10-14",
"notes": [
"Reader: Added support for per-book background image customization",
"Reader: Added option to override book language metadata for improved hyphenation accuracy",
"Sync: Readest sync in KOReader can now be triggered using gesture controls",
"Sync: Fixed a crash in KOReader that occurred when syncing progress without an open book",
"Sync: Improved upload performance with concurrent upload support"
]
},
"0.9.85": {
"date": "2025-10-14",
"notes": [
"TTS: Improved media session control compatibility across more Android systems",
"TTS: Made the TTS icon less distracting during read-aloud mode",
"Settings: Added an option to adjust screen brightness while reading",
"Settings: Added support for custom background images",
"PDF: Fixed an issue where scrolling and panning didnt work correctly when zoomed in",
"Android: Added adaptive launcher icon for better system integration",
"Reader: Added keyboard shortcuts for toggling bookmarks",
"Reader: Annotations are now rendered instantly when opening files"
]
},
"0.9.82": {
"date": "2025-10-01",
"notes": [
"Sync: More reliable syncing between KOReader and Readest",
"MOBI: Fixed an issue where some footnotes in MOBI/AZW files were not parsed correctly",
"Storage: Added support for changing data location on Windows, macOS, Linux, and Android",
"Windows: Portable EXE version now stores all reading data in the directory of the executable",
"Android: Added background TTS support with media session controls",
"WebView: Extended compatibility down to version 92",
"Settings: Added global settings menu to the library page",
"iOS: Fixed an issue where custom theme colors were not handled correctly on older Safari versions",
"TTS: Added more languages for Edge TTS"
]
},
"0.9.81": {
"date": "2025-09-19",
"notes": [
"TTS: Added desktop common media control support when TTS is playing",
"PDF: Disabled swipe-up gesture for toggling the action bar when zoomed in",
"Fonts: Fixed an issue where embedded fonts in ebooks were occasionally not applied",
"Reader: Fixed an issue where newly created highlights sometimes would not appear",
"Reader: Enabled scrolling in the menu when the menu is too long"
]
},
"0.9.80": {
"date": "2025-09-19",
"notes": [
"Accessibility: Added support for popular screen readers on all platforms, making books accessible to readers with visual impairments",
"Sync: Progress is now synced across different versions of the same book by aggregated metadata",
"Library: Groups are now displayed in list view for easier organization",
"Library: Added delete confirmation when removing books from the context menu",
"Fonts: Added support for fonts with subfamilies when importing TTF/OTF font files",
"Layout: Prevented layout shift in Android when the virtual keyboard appears"
]
},
"0.9.78": {
"date": "2025-09-06",
"notes": [
"TTS: Added option to keep a persistent TTS bar at the bottom of the screen",
"TTS: Added previous/next sentence navigation controls in the TTS bar",
"TTS: Added media control support on iOS lock screen and AirPods",
"TTS: Fixed an issue where headings could not be highlighted for TTS",
"Sync: Fixed occasional sync failures between KOReader and Readest",
"Fonts: Grouped font styles into custom font families for easier selection",
"Reader: Improved text selection sensitivity when using a stylus",
"Reader: Books can now be properly closed using the system back button on Android",
"EPUB: Fixed parsing to correctly detect the front cover in some EPUB files",
"PDF: Added zoom level, zoom mode, and spread mode settings for PDFs",
"Reader: Bookmarks can now be edited directly in the sidebar",
"Layout: Prevented layout shift when the virtual keyboard appears on Android",
"TXT: Improved chapter detection and added support for nested table of contents in TXT files"
]
},
"0.9.76": {
"date": "2025-08-30",
"notes": [
"Sync: Moved KOReader sync controls into the reader sidebar with a manual push/pull option",
"Sync: Improved tolerance and reliability for KOReader sync operations",
"Sync: Added support for more KOReader server implementations",
"Fonts: Added support for importing multiple styles within a font family",
"Reader: Fixed an issue where footnotes are empty in some EPUB files",
"Theme: Applied theme background color for PDFs on macOS",
"Reader: Added support for importing AZW3 files on Android",
"Reader: Reduced screen flash when launching the app and opening books",
"Layout: Fixed an issue where the grouping modal would not appear on Linux"
]
},
"0.9.75": {
"date": "2025-08-22",
"notes": [
"Fonts: Added support for importing local TTF and ODF fonts",
"TTS: Reduced the pause between sentences when using Edge TTS",
"TTS: Fixed an issue where voices list could not be opened on older versions of iOS",
"TOC: Fixed an issue where nested TOC items would not collapse properly in some books",
"Translator: Fixed an issue where translations in the popup did not refresh correctly",
"Library: Added option to sort authors with last name first",
"Layout: Fixed mismatch in close button position between the reader and library pages",
"Layout: Book title now remains centered in the available space",
"Layout: Fixed footer bar layout in landscape mode"
]
},
"0.9.72": {
"date": "2025-08-18",
"notes": [
"Fixed Edge TTS voice playback for EPUBs",
"Reduced accidental page flips when toggling toolbars",
"Fixed images with background colors not displaying correctly in some books",
"Added support for custom KOReader Sync Servers on your local network (LAN)"
]
},
"0.9.71": {
"date": "2025-08-13",
"notes": [
"Sync: Added two ways to sync reading progress with KOReader devices",
"EPUB: Applied monospace font settings",
"EPUB: Fixed initial text alignment for some EPUB files",
"PDF: Fixed issue opening large PDF files on Android",
"TTS: Improved book language detection when language code is invalid",
"iOS: Fixed applying system color scheme in auto theme mode",
"Config: Added option to choose reading progress display style (percentage or page number)",
"Library: Added option to delete only the local copy of a book",
"Account: Added 'Reset Password' button in the account page"
]
},
"0.9.69": {
"date": "2025-08-02",
"notes": [
"Updater: Fixed permission issue when updating in standalone reader window",
"Config: Added option to disable doubleclick actions",
"EPUB: Fixed missing images in some EPUB files",
"EPUB: Corrected formatting for book subjects",
"TXT: Improved language detection when parsing TXT files",
"CSS: Resolved issue where custom font colors could not be applied",
"Layout: Corrected cover image width display in 'Fit' mode for list view",
"Layout: Fixed unintended scrolling in reader view when highlighting text"
]
},
"0.9.68": {
"date": "2025-07-30",
"notes": [
"Reader: Files now open in a new window by default on Desktop",
"Translation: Skips translating content inside <pre>, <code>, and <math> tags",
"Performance: Improved multi-part downloading for large books",
"Sync: Resolved issue preventing some PDF files from syncing",
"CSS: Resolved issue with fixed font color in some EPUB files",
"TXT: Enhanced TXT parsing for better compatibility"
]
},
"0.9.67": {
"date": "2025-07-22",
"notes": [
"Reader: Fixed file opening issue when filenames contain commas",
"Translation: Added Yandex Translator as a new translation provider",
"Layout: Hovering over header now reveals macOS traffic light window controls",
"Theme: Reader background color is now customizable for EPUB and PDF",
"Library: Search now includes book format, group names, and descriptions",
"Library: Various improvements to metadata editor and bookshelf management",
"Linux: Fixed social login failure on Linux systems"
]
},
"0.9.66": {
"date": "2025-07-21",
"notes": [
"Layout: Fixed nested table of contents items not expanding in long TOC lists",
"Reader: Opening files from the OS now takes highest priority",
"TTS: Improved voice filtering for some language codes",
"App: Fixed loading issues on older browsers",
"App: Fixed wrong MIME types generated on Linux"
]
},
"0.9.65": {
"date": "2025-07-19",
"notes": [
"Reader: Added support for opening multiple reader windows on desktop",
"Layout: Added visible window borders on Linux",
"TTS: Improved handling of invalid book language",
"TTS: Skipped reading footnote anchor links",
"Translation: Fixed an issue where table of contents entries were not translated",
"Sync: Edited book metadata is now included in sync across devices",
"iOS: Disabled context menu when long-pressing on book covers"
]
},
"0.9.64": {
"date": "2025-07-16",
"notes": [
"Library: Added support to edit book metadata",
"Layout: Fixed bookmark icon placement when the sidebar is pinned",
"Reader: Fixed an issue where links to other chapters in EPUB files did not work",
"Reader: Lightened the highlight color in dark mode for better contrast",
"Reader: Pull-to-refresh gesture is now smoother and more responsive",
"Reader: Removed unintended indentation on images",
"Search: Improved responsiveness of full-text search for faster results"
]
},
"0.9.63": {
"date": "2025-07-07",
"notes": [
"Reader: Fixed links not working in some MOBI books",
"TTS: Fixed an issue where some text was skipped during reading",
"Library: You can now delete only the cloud backup of a book without removing the local copy",
"Performance: Fonts in the font list now load only when displayed for faster startup",
"Performance: Opening large MOBI books is now significantly faster",
"Layout: Fixed overlay scrollbar display in longer TOC items list",
"Layout: Improved grid cover image height in crop mode",
"Layout: Removed unsupported screen orientation lock option on iPad",
"Layout: System context menu no longer appears when selecting text on iPad",
"Translation: Added Thai (th-TH) language support"
]
},
"0.9.62": {
"date": "2025-07-02",
"notes": [
"Subscription: You can now upgrade to Readest Premium and manage your subscription",
"Reader: Added an option to toggle Parallel Reading when viewing multiple books",
"Translation: Added an option to show or hide the original text in translations",
"Layout: TOC on Android now uses an overlay scrollbar for easier navigation",
"Layout: Custom CSS can now also be applied to the library page",
"Fonts: Added three new CJK fonts to choose from",
"Shortcuts: Press ESC to quickly close the search bar"
]
},
"0.9.61": {
"date": "2025-06-26",
"notes": [
"Layout: Fixed view menu width on smaller screens",
"Layout: Added option to crop or fit book covers in library view",
"Reader: You can now apply custom CSS to the reading interface (UI)",
"Reader: Added an option to show remaining pages in the current chapter",
"Settings: Added options to reset settings from the config dialog",
"Import: Fixed encoded filenames when importing TXT files on iOS",
"Linux: Fixed missing app icon on some Linux distributions",
"GitHub: Added donation link to support Readest development"
]
},
"0.9.60": {
"date": "2025-06-22",
"notes": [
"Layout has been improved for iPad devices",
"Screen orientation changes are now smoother on iOS",
"Importing books on iOS during the first launch is now more reliable",
"Font size no longer changes unexpectedly in scrolled mode on iOS",
"Top and bottom safe insets are now ignored when no header or footer is present",
"Interactive books now load correctly on the Desktop platform",
"Translation is now disabled when the primary language is undefined",
"Android: the task list background color has been updated with current theme color"
]
},
"0.9.59": {
"date": "2025-06-19",
"notes": [
"Layout: Image size now adjusts more accurately by converting screen units to pixels properly",
"Layout: Improved header layout on iOS landscape mode — extra spacing has been removed",
"Settings: Top and bottom margin settings are now more intuitive and better constrained"
]
},
"0.9.58": {
"date": "2025-06-18",
"notes": [
"TTS: Translation now works even when TTS is playing in the background",
"TTS: Press T on your keyboard to quickly toggle TTS on or off",
"TTS: Each open book now has its own independent TTS controller",
"Annotations: Annotation tools now function properly while TTS is active",
"Settings: Margins for top, bottom, left, and right can now be adjusted individually",
"Settings: New option to always show the status bar while reading",
"Layout: Reader page now adapts better to device safe areas for a more comfortable layout",
"UI: Added creation timestamps to annotations and made various interface improvements",
"iPad: Multiple columns are now supported in portrait mode",
"iPad: Fixed issue where sidebars couldn't be resized by dragging",
"iPad: Added support for split-screen mode"
]
},
"0.9.57": {
"date": "2025-06-14",
"notes": ["TTS: Fixed an issue to detect custom TTS engines on some Android devices"]
},
"0.9.56": {
"date": "2025-06-13",
"notes": [
"Performance: Improved TOC loading for books with very large chapter lists",
"TTS: Added support for native Android TTS engines (e.g., MultiTTS)",
"TTS: Fixed an issue where the next chapter would not load properly in the background",
"Translation: Improved accuracy and clarity of some Arabic translations",
"Reading: Added support for code syntax highlighting in books with code snippets"
]
},
"0.9.55": {
"date": "2025-06-07",
"notes": [
"Sync: Notes deleted on other devices now correctly sync across all platforms",
"Layout: Now text justification can be unset in the layout settings",
"Translation: Added notification when daily translation quota is exceeded",
"Performance: Reduced unnecessary animations on Android to improve efficiency"
]
},
"0.9.53": {
"date": "2025-06-05",
"notes": [
"Reader: New option to customize book foreground and background colors",
"Reader: Fixed an issue where images appeared too small in some EPUBs",
"EPUB: Improved cover image detection for certain EPUB files",
"TTS: Improved background playback stability on iOS devices",
"Translation: Introduced a daily DeepL translation quota to ensure long-term availability"
]
},
"0.9.52": {
"date": "2025-06-03",
"notes": [
"Library: The search bar now shows the number of books currently displayed",
"Book Details: Book descriptions now support rich HTML formatting",
"Notebook: Added support for writing notes using Markdown",
"Notebook: You can now search within your notes",
"Sync: A sync status item has been added to the View menu",
"TOC: You can now sort the table of contents by page number",
"Reader: Option added to show remaining time in the current chapter"
]
},
"0.9.51": {
"date": "2025-06-01",
"notes": [
"Translator: Table of contents is now included in translations",
"Library Theme: Added light, dark, and system theme options to the library page",
"TTS: Now shows the current sentence and chapter in the media session",
"TTS: Text-to-speech continues from the last read sentence",
"Pagination Fix: Taking notes no longer breaks page turning",
"EPUB Scripts: Added a setting to allow JavaScript in EPUB files"
]
},
"0.9.50": {
"date": "2025-05-28",
"notes": [
"Bilingual TTS: You can now choose voices for each language in bilingual text-to-speech mode",
"Settings Layout: Improved header layout in the settings dialog for different screen sizes",
"CSS Fixes: Corrected anchor text color and fixed image dimensions within paragraphs"
]
},
"0.9.49": {
"date": "2025-05-27",
"notes": [
"Select All in Library: You can now select all books at once when in selection mode",
"More Translation Options: Added support for Azure and Google Translate services",
"Dark Mode Enhancement: New option to invert image colors for better visibility in dark mode",
"Bilingual TTS: Enjoy bilingual text-to-speech for books with content in two languages",
"Full Book Translation: Translate books in any language into bilingual ebooks",
"Privacy Settings: Added a new option to opt-out of telemetry"
]
},
"0.9.43": {
"date": "2025-05-19",
"notes": [
"Enhanced compatibility with Gutenberg and Feedbooks ebooks for better styling",
"Reduced sensitivity of trackpad and mouse during page flips",
"Cloud backup status is now visible for each book on mobile and desktop",
"New option to control scroll overlap when paginating in scroll mode",
"Added Dutch language translations",
"Added more font weight options for built-in fonts",
"Added previous and next section buttons in the footer bar for easier navigation"
]
},
"0.9.41": {
"date": "2025-05-13",
"notes": [
"Improved UI and layout on mobile devices",
"Avatar images are now cached for offline use",
"Book file size is now displayed in the book details view",
"Update status is now correctly shown in the About window",
"TTS control positioning improved for notebook and RTL modes",
"TXT files are segmented by paragraph count if no chapter titles are found",
"Android: App now respects system auto-rotation settings",
"Linux: Updater is disabled on Linux when not using AppImage",
"Linux: Added support for Linux ARMHF builds",
"CSS: Resolved layout and color issues caused by hardcoded CSS"
]
},
"0.9.40": {
"date": "2025-05-08",
"notes": [
"Prevented oversized images from causing layout issues",
"Resolved issue with transient navigation bar on Android 9",
"Action bar now closes properly when the footbar is dismissed",
"Smoother experience when expanding Table of Contents sections",
"Reverted unintended style overrides"
]
},
"0.9.39": {
"date": "2025-05-07",
"notes": [
"Enhanced Navigation: Added location information to the table of contents",
"Enhanced Navigation: Larger touch targets for table of contents expansion icons",
"Screen Orientation Lock: You can now lock your device's screen orientation when reading",
"Quick Access to Recent Books: Option to automatically open your last read book when starting the app",
"Better Language Support: Improved handling of CJK characters in search",
"Enhanced Text-to-Speech: More accurate language detection for TTS",
"Enhanced Text-to-Speech: Text-to-Speech now maintains your position in scroll mode",
"Enhanced Annotations: Better handling of annotations with ruby elements in Japanese books",
"Smoother Scrolling: We've made continuous scrolling more reliable for a seamless reading experience",
"Compact View: Reading view is more compact when header and footer are hidden",
"TXT Parsing: More robust handling of TXT book format"
]
},
"0.9.38": {
"date": "2025-04-29",
"notes": [
"Page Turning with Volume Keys: You can now turn pages using your devices volume buttons",
"Expanded English Voices: More English voices are available across all en locales",
"Theme Editor: Added a primary color picker for easier customization",
"System Fonts: Retrieve system fonts on iOS and Android, with improved font weight and style detection",
"Popup Footnotes: Popup footnotes now inherit the book's font for consistent appearance",
"Better Text Selection: Preserves text selection anchors when spanning paginated content",
"Android Compatibility: Navigation bar auto-hides correctly on Android 10 and below",
"Popup Dialogs: Back key now properly dismisses popup dialogs on Android"
]
},
"0.9.37": {
"date": "2025-04-25",
"notes": [
"Full-Screen Toggle: You can now press F11 to quickly toggle full-screen mode",
"List View: A new list layout is available for your bookshelf",
"Book Details: Book descriptions from metadata are now shown in the details view",
"Enhanced Android behavior: better navigation bar handling and status bar dismissal when resuming",
"TTS now defaults to the books metadata language when needed",
"Synced custom themes reliably across sessions"
]
},
"0.9.36": {
"date": "2025-04-20",
"notes": [
"📥 New download and upload buttons in the book detail dialog for easier file management",
"📂 You can now open files directly in Readest from your file manager on Android and iOS",
"🛠️ Fixed an issue where files with quotation marks in the filename could not be opened",
"📖 Improved the immersive reading experience on the reader page for Android and iOS",
"🌐 Added GuanKiapTsingKhai-T to the list of available CJK fonts"
]
},
"0.9.35": {
"date": "2025-04-15",
"notes": [
"🛠️ Fixed an issue where books without cover images can not be synced across devices",
"📱 Added in-app update support for Android",
"📚 You can now sort books by title or author in your library"
]
},
"0.9.33": {
"date": "2025-04-13",
"notes": [
"New: Redesigned update dialog with a progress bar during downloads for a smoother update experience.",
"New: You can now set header and footer visibility separately for paginated and scroll modes.",
"Fixed layout issues in the bottom configuration panel when using RTL (right-to-left) languages.",
"Fixed TXT file import issues on Android by improving support for content provider file paths.",
"Fixed transformed punctuations when highlighting text with vertical layout.",
"Improved login flow on macOS by handling OAuth with the native ASWebAuthenticationSession."
]
},
"0.9.32": {
"date": "2025-04-09",
"notes": [
"No more resetting of font size and color when you apply custom book styles",
"The underline and squiggly highlight decorations have been adjusted to sit neatly between text lines",
"With more font options available, the font menu is no longer forced in-line",
"LXGW WenKai TC is now part of our CJK font list"
]
},
"0.9.31": {
"date": "2025-04-08",
"notes": [
"iOS: Text-to-Speech (TTS) now works in the background",
"Android: Import files from native file manager",
"Desktop: Add option to keep window on top",
"Vertical layout for highlighting tools",
"Added options to auto-stop TTS after timeout",
"Added book search functionality in bookshelf",
"Improved font support for CJK users"
]
},
"0.9.30": {
"date": "2025-04-05",
"notes": [
"Added fixed storage quota when running the app in self-hosted mode",
"Link colors will only change when you override fonts",
"Added cache for native files for better performance"
]
},
"0.9.29": {
"date": "2025-04-02",
"notes": [
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
set -e
VERSION=$(jq -r '.version' package.json)
MANIFEST="./src-tauri/gen/android/app/src/main/AndroidManifest.xml"
INSTALL_PERMISSION_LINE='<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>'
STORAGE_PERMISSION_LINE='<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>'
ised() {
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "$@"
else
sed -i "$@"
fi
return $?
}
# --- REMOVE PERMISSION BEFORE BUILD ---
if grep -q 'REQUEST_INSTALL_PACKAGES' "$MANIFEST"; then
echo "🧹 Removing REQUEST_INSTALL_PACKAGES from AndroidManifest.xml"
if ised "/REQUEST_INSTALL_PACKAGES/d" "$MANIFEST"; then
echo "✅ Successfully removed REQUEST_INSTALL_PACKAGES"
else
echo "❌ Failed to remove REQUEST_INSTALL_PACKAGES" >&2
exit 1
fi
fi
if grep -q 'MANAGE_EXTERNAL_STORAGE' "$MANIFEST"; then
echo "🧹 Removing MANAGE_EXTERNAL_STORAGE from AndroidManifest.xml"
if ised "/MANAGE_EXTERNAL_STORAGE/d" "$MANIFEST"; then
echo "✅ Successfully removed MANAGE_EXTERNAL_STORAGE"
else
echo "❌ Failed to remove MANAGE_EXTERNAL_STORAGE" >&2
exit 1
fi
fi
echo "🚀 Running: pnpm tauri android build"
pnpm tauri android build --config src-tauri/tauri.playstore.conf.json
# --- ADD PERMISSION BACK AFTER BUILD ---
if ! grep -q 'REQUEST_INSTALL_PACKAGES' "$MANIFEST"; then
echo "♻️ Restoring REQUEST_INSTALL_PACKAGES in AndroidManifest.xml"
ised "/android.permission.INTERNET/a\\
$INSTALL_PERMISSION_LINE
" "$MANIFEST"
fi
if ! grep -q 'MANAGE_EXTERNAL_STORAGE' "$MANIFEST"; then
echo "♻️ Restoring MANAGE_EXTERNAL_STORAGE in AndroidManifest.xml"
ised "/android.permission.WRITE_EXTERNAL_STORAGE/a\\
$STORAGE_PERMISSION_LINE
" "$MANIFEST"
fi
source .env.google-play.local
if [[ -z "$GOOGLE_PLAY_JSON_KEY_FILE" ]]; then
echo "❌ GOOGLE_PLAY_JSON_KEY_FILE is not set"
exit 1
fi
cd ../../
fastlane android upload_production
@@ -1,3 +1,22 @@
#!/bin/bash
set -e
echo "Updating bundleVersion in tauri.appstore.conf.json..."
CONFIG_FILE="src-tauri/tauri.appstore.conf.json"
CURRENT_DATE=$(date "+%Y%m%d.%H%M%S")
if [ ! -f "$CONFIG_FILE" ]; then
echo "Error: Config file $CONFIG_FILE not found!"
exit 1
fi
TMP_FILE=$(mktemp)
cat "$CONFIG_FILE" | jq --arg version "$CURRENT_DATE" '.bundle.macOS.bundleVersion = $version' > "$TMP_FILE"
mv "$TMP_FILE" "$CONFIG_FILE"
echo "Updated bundleVersion to $CURRENT_DATE"
echo "Building macOS universal app for App Store..."
pnpm run build-macos-universial-appstore
BUNDLE_DIR=../../target/universal-apple-darwin/release/bundle/macos
+183
View File
@@ -0,0 +1,183 @@
#!/bin/bash
# Sync release notes from JSON to XML AppData file
# Usage: ./sync_release_notes.sh [json_file] [xml_file]
#
# Description:
# Extracts release information from a JSON file and updates the <releases>
# section in an AppData XML file, then calculates the SHA256 checksum.
#
# Arguments:
# json_file: Path to JSON file (default: releases.json)
# xml_file: Path to XML file (default: appdata.xml)
set -e
set -o pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Helper functions
log_info() {
echo -e "${GREEN}${NC} $1"
}
log_warn() {
echo -e "${YELLOW}${NC} $1"
}
log_error() {
echo -e "${RED}${NC} $1" >&2
}
# Check if required commands are available
if ! command -v jq >/dev/null 2>&1; then
log_error "jq is required but not installed."
echo "Install it with: apt-get install jq (Debian/Ubuntu) or brew install jq (macOS)"
exit 1
fi
# Parse arguments
JSON_FILE="${1:-releases.json}"
XML_FILE="${2:-appdata.xml}"
# Validate input files
if [ ! -f "$JSON_FILE" ]; then
log_error "JSON file '$JSON_FILE' not found"
exit 1
fi
if [ ! -f "$XML_FILE" ]; then
log_error "XML file '$XML_FILE' not found"
exit 1
fi
# Validate JSON format
if ! jq empty "$JSON_FILE" 2>/dev/null; then
log_error "Invalid JSON format in '$JSON_FILE'"
exit 1
fi
# Check if releases key exists
if ! jq -e '.releases' "$JSON_FILE" >/dev/null 2>&1; then
log_error "No 'releases' key found in JSON file"
exit 1
fi
echo "================================================"
echo "Release Notes Sync Tool"
echo "================================================"
echo "Source: $JSON_FILE"
echo "Target: $XML_FILE"
echo ""
# Create backup
BACKUP_FILE="${XML_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$XML_FILE" "$BACKUP_FILE"
log_info "Created backup: $BACKUP_FILE"
# Create temporary files
TEMP_XML=$(mktemp)
TEMP_RELEASES=$(mktemp)
# Cleanup function
cleanup() {
rm -f "$TEMP_XML" "$TEMP_RELEASES"
}
trap cleanup EXIT
# Extract releases from JSON and convert to XML format
log_info "Extracting releases from JSON..."
RELEASE_COUNT=$(jq '.releases | length' "$JSON_FILE")
echo " Found $RELEASE_COUNT releases"
jq -r '
.releases | to_entries | .[0:10] | .[] |
" <release version=\"\(.key)\" date=\"\(.value.date)\">
<description>
<ul>
" +
((.value.notes | map(" <li>\(.)</li>")) | join("\n")) +
"
</ul>
</description>
</release>"
' "$JSON_FILE" > "$TEMP_RELEASES"
# Find the releases section in XML and replace it
log_info "Updating XML file..."
awk -v releases="$TEMP_RELEASES" '
BEGIN { in_releases = 0; printed_releases = 0 }
/<releases>/ {
print $0
if (printed_releases == 0) {
while ((getline line < releases) > 0) {
print line
}
close(releases)
printed_releases = 1
}
in_releases = 1
next
}
/<\/releases>/ {
in_releases = 0
print $0
next
}
in_releases { next }
{ print }
' "$XML_FILE" > "$TEMP_XML"
# Validate the generated XML
if ! grep -q "<releases>" "$TEMP_XML" || ! grep -q "</releases>" "$TEMP_XML"; then
log_error "Failed to generate valid XML structure"
log_warn "Restoring from backup..."
mv "$BACKUP_FILE" "$XML_FILE"
exit 1
fi
# Remove backup if everything is fine
rm "$BACKUP_FILE"
# Replace original file
mv "$TEMP_XML" "$XML_FILE"
log_info "XML file updated successfully"
# Calculate SHA256 checksum
echo ""
log_info "Calculating SHA256 checksum..."
if command -v sha256sum >/dev/null 2>&1; then
CHECKSUM=$(sha256sum "$XML_FILE" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
CHECKSUM=$(shasum -a 256 "$XML_FILE" | awk '{print $1}')
else
log_error "Neither sha256sum nor shasum found"
exit 1
fi
# Save checksum to file
CHECKSUM_FILE="${XML_FILE}.sha256"
echo "$CHECKSUM $XML_FILE" > "$CHECKSUM_FILE"
echo ""
echo "================================================"
echo "Summary"
echo "================================================"
echo " Updated file: $XML_FILE"
echo " Backup file: $BACKUP_FILE"
echo " Checksum file: $CHECKSUM_FILE"
echo " SHA256: $CHECKSUM"
echo " Releases: $RELEASE_COUNT"
echo ""
log_info "Sync completed successfully!"
echo ""
echo "To verify the checksum, run:"
if command -v sha256sum >/dev/null 2>&1; then
echo " sha256sum -c $CHECKSUM_FILE"
else
echo " shasum -a 256 -c $CHECKSUM_FILE"
fi
+33 -18
View File
@@ -1,6 +1,6 @@
[package]
name = "Readest"
version = "0.2.1"
version = "0.2.2"
description = "Your online library"
authors = ["Bilingify LLC"]
license = ""
@@ -14,47 +14,62 @@ rust-version = "1.77.2"
name = "readestlib"
crate-type = ["staticlib", "cdylib", "lib"]
[features]
# Internal feature to suppress warnings from old objc crate
cargo-clippy = []
[build-dependencies]
tauri-build = { version = "2.0.3", features = [] }
tauri-build = { version = "2", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
thiserror = "2"
walkdir = "2"
tokio = { version = "1", features = ["fs"] }
tokio-util = { version = "0.7", features = ["codec"] }
futures-util = "0.3"
futures = "0.3.31"
read-progress-stream = "1.0.0"
reqwest = { version = "0.12", default-features = false, features = [
"json",
"stream",
] }
# FIXME: remove the devtools feature in production
tauri = { version = "2.4.0", features = [ "protocol-asset", "devtools"] }
tauri-build = "2.1.0"
tauri-plugin-log = "2.3.1"
tauri-plugin-fs = "2.2.0"
tauri-plugin-dialog = "2.2.0"
tauri-plugin-os = "2.2.1"
tauri-plugin-http = "2.4.2"
tauri-plugin-shell = "2.2.0"
tauri-plugin-process = "2.2.0"
tauri = { version = "2", features = [ "protocol-asset" ] }
tauri-build = "2"
tauri-plugin-log = "2"
tauri-plugin-fs = "2"
tauri-plugin-dialog = "2"
tauri-plugin-os = "2"
tauri-plugin-http = { version = "2", features = ["dangerous-settings"] }
tauri-plugin-shell = "2"
tauri-plugin-process = "2"
tauri-plugin-oauth = "2"
tauri-plugin-opener = "2.2.2"
tauri-plugin-opener = "2"
tauri-plugin-deep-link = "2"
tauri-plugin-sign-in-with-apple = "1.0.2"
tauri-plugin-haptics = "2.2.3"
tauri-plugin-haptics = "2"
tauri-plugin-persisted-scope = "2"
tauri-plugin-native-bridge = { path = "./plugins/tauri-plugin-native-bridge" }
tauri-plugin-native-tts = { path = "./plugins/tauri-plugin-native-tts" }
tauri-plugin-websocket = "2"
tauri-plugin-sharekit = "0.3"
[target."cfg(target_os = \"macos\")".dependencies]
rand = "0.8"
cocoa = "0.25"
objc = "0.2.7"
rand = "0.8"
objc-foundation = "0.1.1"
objc_id = "0.1.1"
block = "0.1.6"
objc2 = "0.6"
objc2-authentication-services = "0.3"
objc2-foundation = { version = "0.3", features = ["NSError", "NSArray"] }
[target.'cfg(any(target_os = "macos", windows, target_os = "linux"))'.dependencies]
tauri-plugin-cli = "2"
tauri-plugin-single-instance = "2.2.0"
tauri-plugin-single-instance = "2"
tauri-plugin-updater = "2"
tauri-plugin-window-state = "2.2.0"
font-enumeration = "0.9.0"
tauri-plugin-window-state = "2"
discord-rich-presence = "1.0.0"
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
</dict>
</plist>
+362
View File
@@ -0,0 +1,362 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<false/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIHomeIndicatorAutoHidden</key>
<true/>
<key>UIRequiresFullScreen</key>
<false/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>EPUB Document</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.idpf.epub-container</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>PDF Document</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.adobe.pdf</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>FB2 Document</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.readest.fb2</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>CBZ Archive</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.readest.cbz</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>MOBI Document</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.mobipocket.mobi</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>AZW Document</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.amazon.azw</string>
<string>com.amazon.azw3</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>Text File</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.plain-text</string>
</array>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>org.idpf.epub-container</string>
<key>UTTypeDescription</key>
<string>EPUB Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.composite-content</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>epub</string>
</array>
<key>public.mime-type</key>
<string>application/epub+zip</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.adobe.pdf</string>
<key>UTTypeDescription</key>
<string>PDF Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.composite-content</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>pdf</string>
</array>
<key>public.mime-type</key>
<string>application/pdf</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.readest.fb2</string>
<key>UTTypeDescription</key>
<string>FB2 Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>fb2</string>
</array>
<key>public.mime-type</key>
<string>application/xml</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.readest.cbz</string>
<key>UTTypeDescription</key>
<string>CBZ Archive</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>cbz</string>
</array>
<key>public.mime-type</key>
<string>application/x-cbz</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>org.mobipocket.mobi</string>
<key>UTTypeDescription</key>
<string>MOBI Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mobi</string>
</array>
<key>public.mime-type</key>
<string>application/x-mobipocket-ebook</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.amazon.azw</string>
<key>UTTypeDescription</key>
<string>AZW Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>azw</string>
<string>azw3</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.amazon.ebook</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>public.plain-text</string>
<key>UTTypeDescription</key>
<string>Text File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>txt</string>
</array>
<key>public.mime-type</key>
<string>text/plain</string>
</dict>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>org.idpf.epub-container</string>
<key>UTTypeDescription</key>
<string>EPUB Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>epub</string>
</array>
<key>public.mime-type</key>
<string>application/epub+zip</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.readest.fb2</string>
<key>UTTypeDescription</key>
<string>FB2 Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>fb2</string>
</array>
<key>public.mime-type</key>
<string>application/xml</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.readest.cbz</string>
<key>UTTypeDescription</key>
<string>CBZ Archive</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>cbz</string>
</array>
<key>public.mime-type</key>
<string>application/x-cbz</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>org.mobipocket.mobi</string>
<key>UTTypeDescription</key>
<string>MOBI Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mobi</string>
</array>
<key>public.mime-type</key>
<string>application/x-mobipocket-ebook</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.amazon.azw</string>
<key>UTTypeDescription</key>
<string>AZW Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>azw</string>
<string>azw3</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.amazon.ebook</string>
</dict>
</dict>
</array>
</dict>
</plist>
+62
View File
@@ -1,3 +1,65 @@
use std::{env, fs, path::PathBuf, process::Command};
fn main() {
println!("cargo:rerun-if-changed=../extensions/windows-thumbnail/src");
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
if target_os == "windows" {
build_windows_thumbnail();
}
tauri_build::build()
}
fn build_windows_thumbnail() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let dll_crate_dir = manifest_dir
.join("..")
.join("extensions")
.join("windows-thumbnail");
let dll_crate_manifest = dll_crate_dir.join("Cargo.toml");
let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".into());
let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
cmd.arg("build")
.arg("--package")
.arg("windows_thumbnail")
.arg("--manifest-path")
.arg(&dll_crate_manifest);
if profile == "release" {
cmd.arg("--release");
}
let target_triple = env::var("TARGET").unwrap_or_default();
let host_triple = env::var("HOST").unwrap_or_default();
if !target_triple.is_empty() && target_triple != host_triple {
cmd.arg("--target").arg(&target_triple);
}
let status = cmd
.status()
.expect("Failed to run cargo build for windows_thumbnail");
if !status.success() {
panic!("Failed to build windows_thumbnail DLL");
}
let dll_name = "windows_thumbnail.dll";
let candidate_paths = [
dll_crate_dir.join("target").join(&profile).join(dll_name),
dll_crate_dir
.join("target")
.join(&target_triple)
.join(&profile)
.join(dll_name),
];
let dll_src = candidate_paths
.iter()
.find(|p| p.exists())
.expect("Failed to find built windows_thumbnail DLL");
let dll_dest = &dll_crate_dir.join("target").join(dll_name);
fs::copy(dll_src, dll_dest).expect("Failed to copy windows_thumbnail DLL");
println!("cargo:rerun-if-changed={}", dll_dest.display());
}
@@ -2,7 +2,7 @@
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "enables the default permissions",
"windows": ["main"],
"windows": ["main", "updater", "reader-*"],
"permissions": [
"core:default",
"fs:default",
@@ -39,17 +39,84 @@
}
]
},
{
"identifier": "fs:allow-cache-read",
"allow": [
{
"path": "$APPCACHE/**/*"
},
{
"path": "/private/var/mobile/Containers/Data/Application/**/*"
}
]
},
{
"identifier": "fs:allow-cache-write",
"allow": [
{
"path": "$APPCACHE/**/*"
},
{
"path": "/private/var/mobile/Containers/Data/Application/**/*"
}
]
},
{
"identifier": "fs:scope",
"allow": [
{
"path": "**/Readest"
},
{
"path": "**/Readest/**/*"
},
{
"path": "**/last-book-cover.png"
}
]
},
{
"identifier": "http:default",
"allow": [
{
"url": "https://*.readest.com"
},
{
"url": "https://github.com/readest/*"
},
{
"url": "https://*.deepl.com"
},
{
"url": "https://*.cloudflarestorage.com"
},
{
"url": "https://edge.microsoft.com"
},
{
"url": "https://translate.toil.cc"
},
{
"url": "https://*.microsofttranslator.com"
},
{
"url": "https://translate.googleapis.com"
},
{
"url": "http://*:*"
},
{
"url": "https://*:*"
},
{
"url": "http://*"
},
{
"url": "https://*"
}
]
},
"websocket:default",
"dialog:default",
"os:default",
"core:window:default",
@@ -57,12 +124,17 @@
"core:window:allow-center",
"core:window:allow-minimize",
"core:window:allow-maximize",
"core:window:allow-unmaximize",
"core:window:allow-set-size",
"core:window:allow-set-focus",
"core:window:allow-is-maximized",
"core:window:allow-start-dragging",
"core:window:allow-toggle-maximize",
"core:window:allow-set-fullscreen",
"core:window:allow-set-always-on-top",
"core:window:allow-destroy",
"core:webview:allow-create-webview-window",
"core:path:allow-resolve-directory",
"log:default",
"shell:default",
"process:default",
@@ -72,11 +144,41 @@
"oauth:allow-cancel",
"sign-in-with-apple:default",
"opener:default",
{
"identifier": "opener:allow-open-url",
"allow": [
{
"url": "alipays:*"
}
]
},
{
"identifier": "shell:allow-spawn",
"allow": [
{
"name": "start-readest",
"cmd": "cmd",
"args": ["/C", "start", "", { "validator": "^.*Readest(.*)\\.exe$" }]
},
{
"name": "chmod-appimage",
"cmd": "chmod",
"args": ["+x", { "validator": "^.*Readest(.*)\\.AppImage$" }]
},
{
"name": "launch-appimage",
"cmd": "setsid",
"args": [{ "validator": "^.*Readest(.*)\\.AppImage$" }]
}
]
},
"haptics:allow-vibrate",
"haptics:allow-impact-feedback",
"haptics:allow-notification-feedback",
"haptics:allow-selection-feedback",
"native-bridge:default",
"deep-link:default"
"deep-link:default",
"sharekit:default",
"native-tts:default",
"native-bridge:default"
]
}
@@ -1,10 +1,7 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop-capability",
"windows": ["main"],
"windows": ["main", "updater", "reader-*"],
"platforms": ["linux", "macOS", "windows"],
"permissions": [
"updater:default",
"cli:default"
]
"permissions": ["updater:default", "cli:default"]
}
@@ -15,28 +15,29 @@ val tauriProperties = Properties().apply {
}
android {
compileSdk = 34
compileSdk = 36
namespace = "com.bilingify.readest"
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.bilingify.readest"
minSdk = 26
targetSdk = 34
targetSdk = 36
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
}
signingConfigs {
create("release") {
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
if (keystorePropertiesFile.exists()) {
create("signing") {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["password"] as String
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["password"] as String
}
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["password"] as String
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["password"] as String
}
}
buildTypes {
@@ -45,14 +46,26 @@ android {
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
if (keystorePropertiesFile.exists()) {
signingConfig = signingConfigs.getByName("signing")
}
packaging {
jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
if (keystorePropertiesFile.exists()) {
signingConfig = signingConfigs.getByName("signing")
}
proguardFiles(
*fileTree(".") { include("**/*.pro") }
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
.toList().toTypedArray()
)
}
}
kotlinOptions {
@@ -68,13 +81,13 @@ rust {
}
dependencies {
implementation("androidx.webkit:webkit:1.6.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.activity:activity-ktx:1.9.3")
implementation("com.google.android.material:material:1.8.0")
implementation("androidx.webkit:webkit:1.14.0")
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.activity:activity-ktx:1.10.1")
implementation("com.google.android.material:material:1.12.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
}
apply(from = "tauri.build.gradle.kts")
apply(from = "tauri.build.gradle.kts")
@@ -1,30 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<!-- AndroidTV support -->
<uses-feature android:name="android.software.leanback" android:required="false" />
<application
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:largeHeap="true"
android:enableOnBackInvokedCallback="false"
android:label="@string/app_name"
android:theme="@style/Theme.readest"
android:hardwareAccelerated="true"
android:usesCleartextTraffic="${usesCleartextTraffic}">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:launchMode="singleTask"
android:label="@string/main_activity_title"
android:hardwareAccelerated="true"
android:name=".MainActivity"
android:exported="true">
<intent-filter android:label="oauth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="readest" android:host="auth-callback" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="application/epub+zip" />
<data android:mimeType="application/pdf" />
<data android:mimeType="application/fb2" />
<data android:mimeType="application/x-fb2" />
<data android:mimeType="application/mobi"/>
<data android:mimeType="application/azw"/>
<data android:mimeType="application/azw3"/>
<data android:mimeType="application/x-mobipocket-ebook" />
<data android:mimeType="application/vnd.amazon.ebook" />
<data android:mimeType="application/vnd.amazon.mobi8-ebook" />
<data android:mimeType="application/vnd.comicbook+zip" />
<data android:mimeType="application/x-cbz" />
<data android:mimeType="application/zip" />
<data android:mimeType="text/plain" />
<data android:mimeType="application/octet-stream"/>
<data android:mimeType="application/x-font-ttf"/>
<data android:mimeType="application/x-font-otf"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.epub" />
<data android:pathPattern=".*\\.pdf" />
<data android:pathPattern=".*\\.fb2" />
<data android:pathPattern=".*\\.fb2.zip" />
<data android:pathPattern=".*\\.mobi" />
<data android:pathPattern=".*\\.azw" />
<data android:pathPattern=".*\\.azw3" />
<data android:pathPattern=".*\\.cbz" />
<data android:pathPattern=".*\\.zip" />
<data android:pathPattern=".*\\.txt" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="*/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="*/*"/>
</intent-filter>
<intent-filter android:label="oauth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="readest" android:host="auth-callback" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -32,18 +102,38 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
<intent-filter android:autoVerify="true">
<intent-filter android:autoVerify="true" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="http" />
<data android:host="web.readest.com" />
</intent-filter>
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
</activity>
<receiver
android:name="androidx.media.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<service
android:name="com.readest.native_tts.MediaPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
@@ -2,50 +2,258 @@ package com.bilingify.readest
import android.os.Build
import android.os.Bundle
import android.content.Intent
import android.view.KeyEvent
import android.view.MotionEvent
import android.webkit.WebView
import android.net.Uri
import android.view.View
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.util.Log
import android.content.Intent
import android.graphics.Color
import android.app.ActivityManager
import android.content.res.Configuration
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import androidx.activity.enableEdgeToEdge
import androidx.activity.OnBackPressedCallback
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import app.tauri.plugin.JSArray
import app.tauri.plugin.JSObject
import com.readest.native_bridge.KeyDownInterceptor
import com.readest.native_bridge.NativeBridgePlugin
class MainActivity : TauriActivity() {
class MainActivity : TauriActivity(), KeyDownInterceptor {
private var wv: WebView? = null
private var interceptVolumeKeysEnabled = false
private var interceptBackKeyEnabled = false
override fun onWebViewCreate(webView: WebView) {
wv = webView
}
private val keyEventMap = mapOf(
KeyEvent.KEYCODE_BACK to "Back",
KeyEvent.KEYCODE_VOLUME_DOWN to "VolumeDown",
KeyEvent.KEYCODE_VOLUME_UP to "VolumeUp"
)
override fun interceptVolumeKeys(enabled: Boolean) {
Log.d("MainActivity", "Intercept volume keys: $enabled")
interceptVolumeKeysEnabled = enabled
}
override fun interceptBackKey(enabled: Boolean) {
Log.d("MainActivity", "Intercept back key: $enabled")
interceptBackKeyEnabled = enabled
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
val action = when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> "touchstart"
MotionEvent.ACTION_UP -> "touchend"
MotionEvent.ACTION_CANCEL -> "touchcancel"
MotionEvent.ACTION_POINTER_DOWN -> "touchstart"
MotionEvent.ACTION_POINTER_UP -> "touchend"
else -> null
}
action?.let { eventType ->
val pointerIndex = event.actionIndex
val pointerId = event.getPointerId(pointerIndex)
val x = event.getX(pointerIndex)
val y = event.getY(pointerIndex)
val pressure = event.getPressure(pointerIndex)
wv?.evaluateJavascript(
"""
try {
if (window.onNativeTouch) {
window.onNativeTouch({
type: "$eventType",
pointerId: $pointerId,
x: $x,
y: $y,
pressure: $pressure,
pointerCount: ${event.pointerCount},
timestamp: ${event.eventTime}
});
}
} catch (err) {
console.error('Native touch error:', err);
}
""".trimIndent(),
null
)
}
return super.dispatchTouchEvent(event)
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
val keyCode = event.keyCode
val keyName = keyEventMap[keyCode]
if (keyName != null) {
val shouldIntercept = when (keyCode) {
KeyEvent.KEYCODE_BACK -> interceptBackKeyEnabled
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> interceptVolumeKeysEnabled
else -> false
}
if (shouldIntercept) {
wv?.evaluateJavascript(
"""
try { window.onNativeKeyDown("$keyName", $keyCode); } catch (_) {}
""".trimIndent(),
null
)
return true
}
}
}
return super.dispatchKeyEvent(event)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
val keyName = keyEventMap[keyCode]
if (keyName != null) {
wv?.evaluateJavascript(
"""
try {
window.onNativeKeyDown("$keyName", $keyCode)
} catch (err) {
false
}
""".trimIndent()
) { result ->
run {
if (result.equals("true", ignoreCase = true)) {
Log.d("Key Event", "Key event $keyName intercepted")
}
}
}
return when (keyCode) {
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> {
if (interceptVolumeKeysEnabled) {
true
} else {
super.onKeyDown(keyCode, event)
}
}
KeyEvent.KEYCODE_BACK -> {
if (interceptBackKeyEnabled) {
true
} else {
super.onKeyDown(keyCode, event)
}
}
else -> super.onKeyDown(keyCode, event)
}
}
return super.onKeyDown(keyCode, event)
}
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
hideSystemUI()
handleIncomingIntent(intent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setTaskDescription(
ActivityManager.TaskDescription(
getString(R.string.app_name),
null,
Color.TRANSPARENT
)
)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
OnBackInvokedCallback {
Log.d("MainActivity", "Back invoked callback triggered ${interceptBackKeyEnabled}")
if (interceptBackKeyEnabled) {
Log.d("MainActivity", "Back intercepted (OnBackInvokedCallback)")
wv?.evaluateJavascript(
"""window.onNativeKeyDown("Back", ${KeyEvent.KEYCODE_BACK});""",
null
)
} else {
finish()
}
}
)
}
onBackPressedDispatcher.addCallback(this,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (interceptBackKeyEnabled) {
Log.d("MainActivity", "Back intercepted (OnBackPressedDispatcher)")
wv?.evaluateJavascript(
"""window.onNativeKeyDown("Back", ${KeyEvent.KEYCODE_BACK});""",
null
)
} else {
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
}
}
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
NativeBridgePlugin.getInstance()?.handleActivityResult(requestCode, resultCode, data)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent?.let { handleIncomingIntent(it) }
}
val uri = intent.data ?: return
if (uri.scheme == "readest" && uri.host == "auth-callback") {
val result = JSObject().apply {
put("redirectUrl", uri.toString())
private fun handleIncomingIntent(intent: Intent) {
when (intent.action) {
Intent.ACTION_SEND -> {
if (intent.type != null) {
handleSingleFile(intent)
}
}
Intent.ACTION_SEND_MULTIPLE -> {
if (intent.type != null) {
handleMultipleFiles(intent)
}
}
NativeBridgePlugin.pendingInvoke?.resolve(result)
NativeBridgePlugin.pendingInvoke = null
}
}
}
private fun hideSystemUI() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.decorView.windowInsetsController?.let { controller ->
controller.hide(WindowInsets.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
private fun handleSingleFile(intent: Intent) {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
uri?.let { fileUri ->
val payload = JSObject().apply {
var urls = JSArray()
urls.put(fileUri.toString())
put("urls", urls)
}
} else {
@Suppress("DEPRECATION")
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
)
NativeBridgePlugin.getInstance()?.triggerEvent("shared-intent", payload)
}
}
private fun handleMultipleFiles(intent: Intent) {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
uris?.let { fileUris ->
val payload = JSObject().apply {
var urls = JSArray()
fileUris.forEach { urls.put(it.toString()) }
put("urls", urls)
}
NativeBridgePlugin.getInstance()?.triggerEvent("shared-intent", payload)
}
}
}
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
@@ -0,0 +1,8 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="#FF323130" />
</item>
<item android:gravity="center" android:width="120dp" android:height="120dp">
<bitmap android:src="@drawable/splash_icon" />
</item>
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground>
<inset
android:drawable="@mipmap/ic_launcher_foreground"
android:inset="22%"/>
</foreground>
</adaptive-icon>
@@ -2,8 +2,13 @@
<!-- Base application theme. -->
<style name="Theme.readest" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:windowBackground">@drawable/splash_background</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:fitsSystemWindows">false</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>
@@ -0,0 +1,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

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