Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f53546cc01 | |||
| 594b078fad | |||
| ac1b2f5ce4 | |||
| 648d21062f | |||
| 89d715ce6b | |||
| bd527a02ef | |||
| 11117c1b54 | |||
| ba25d5b8fe | |||
| 31cb4b994a | |||
| 72ef618af1 | |||
| 936fd223bb | |||
| 6d26438d2d | |||
| 5eb5a55c4c | |||
| 6cd86d1422 | |||
| 9783c4d5e3 |
@@ -45,7 +45,7 @@ body:
|
||||
label: LNReader version
|
||||
description: You can find your LNReader version in **More → About**.
|
||||
placeholder: |
|
||||
Example: "2.1.0"
|
||||
Example: "2.1.1"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -88,7 +88,7 @@ body:
|
||||
required: true
|
||||
- label: If this is an issue with a plugin, I should be opening an issue in the [plugins repository](https://github.com/lnreader/lnreader-plugins/issues/new/choose).
|
||||
required: true
|
||||
- label: I have updated the app to version **[2.1.0](https://github.com/lnreader/lnreader/releases/latest)**.
|
||||
- label: I have updated the app to version **[2.1.1](https://github.com/lnreader/lnreader/releases/latest)**.
|
||||
required: true
|
||||
- label: I will fill out all of the requested information in this form.
|
||||
required: true
|
||||
|
||||
@@ -34,7 +34,7 @@ body:
|
||||
required: true
|
||||
- label: If this is an issue with a source, I should be opening an issue in the [sources repository](https://github.com/lnreader/lnreader-sources/issues/new/choose).
|
||||
required: true
|
||||
- label: I have updated the app to version **[2.1.0](https://github.com/lnreader/lnreader/releases/latest)**.
|
||||
- label: I have updated the app to version **[2.1.1](https://github.com/lnreader/lnreader/releases/latest)**.
|
||||
required: true
|
||||
- label: I will fill out all of the requested information in this form.
|
||||
required: true
|
||||
|
||||
@@ -149,6 +149,7 @@ jobs:
|
||||
"app/build/outputs/apk/preRelease/$PRERELEASE_APK_NAME"
|
||||
|
||||
- name: Upload Preview APK
|
||||
id: upload-nightly
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.PRERELEASE_ARTIFACT_NAME }}
|
||||
@@ -156,3 +157,34 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
compression-level: 0
|
||||
|
||||
- name: Notify Discord
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_NIGHTLY_WEBHOOK }}
|
||||
ARTIFACT_URL: ${{ steps.upload-nightly.outputs.artifact-url }}
|
||||
run: |
|
||||
short_sha="${GITHUB_SHA::8}"
|
||||
message="[${GITHUB_REPOSITORY}] New nightly build published: \`${short_sha}\`"
|
||||
|
||||
payload=$(jq -n \
|
||||
--arg title "$message" \
|
||||
--arg url "$ARTIFACT_URL" \
|
||||
'{
|
||||
username: "GitHub",
|
||||
avatar_url: "https://github.com/github.png",
|
||||
embeds: [{
|
||||
author: {
|
||||
name: "github-actions[bot]",
|
||||
icon_url: "https://github.com/github.png"
|
||||
},
|
||||
title: $title,
|
||||
url: $url,
|
||||
color: 3092790
|
||||
}]
|
||||
}')
|
||||
|
||||
curl --fail-with-body \
|
||||
--request POST \
|
||||
--header "Content-Type: application/json" \
|
||||
--data "$payload" \
|
||||
"$DISCORD_WEBHOOK_URL"
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Repository Conventions
|
||||
|
||||
- Do not add or modify tests unless explicitly requested.
|
||||
@@ -19,9 +19,12 @@ import Main from './src/navigators/Main';
|
||||
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
||||
import { useInitDatabase } from '@database/db';
|
||||
import { useInitializeAppServices } from '@hooks/common/useInitializeAppServices';
|
||||
import { opSqliteAdapter } from './src/rozenite/opSqliteAdapter';
|
||||
import { useRozeniteSqlitePlugin } from '@rozenite/sqlite-plugin';
|
||||
import { ThemeProvider, useTheme } from '@hooks/persisted/useTheme';
|
||||
|
||||
enableFreeze(true);
|
||||
const sqliteAdapters = __DEV__ && opSqliteAdapter ? [opSqliteAdapter] : [];
|
||||
|
||||
const ThemedPaperProvider = ({ children }: PropsWithChildren) => {
|
||||
const theme = useTheme();
|
||||
@@ -41,6 +44,7 @@ const ThemedPaperProvider = ({ children }: PropsWithChildren) => {
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
useRozeniteSqlitePlugin({ adapters: sqliteAdapters });
|
||||
const { success: databaseReady, error: databaseError } = useInitDatabase();
|
||||
const { ready: servicesReady, error: servicesError } =
|
||||
useInitializeAppServices(Boolean(databaseReady));
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
<a href="https://github.com/lnreader/lnreader/releases/latest">
|
||||
<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/lnreader/lnreader?label=Stable&labelColor=0d7377&color=084c4e&style=flat">
|
||||
</a>
|
||||
<a href="https://github.com/lnreader/lnreader/releases/latest">
|
||||
<img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/lnreader/lnreader?include_prereleases&sort=semver&label=Beta&labelColor=3d3d5c&color=2a2a47&style=flat">
|
||||
<a href="https://github.com/lnreader/lnreader/actions/workflows/build.yml">
|
||||
<img alt="Build Preview" src="https://github.com/lnreader/lnreader/actions/workflows/build.yml/badge.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"expo": {
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"name": "LNReader",
|
||||
"slug": "LNReader",
|
||||
"scheme": "lnreader",
|
||||
@@ -47,7 +47,7 @@
|
||||
]
|
||||
],
|
||||
"android": {
|
||||
"versionCode": 4196352,
|
||||
"versionCode": 4196353,
|
||||
"package": "com.rajarsheechatterjee.LNReader",
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/native/ic_launcher_foreground.png",
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
DROP TRIGGER IF EXISTS `update_novel_stats`;--> statement-breakpoint
|
||||
DROP TRIGGER IF EXISTS `update_novel_stats_on_update`;--> statement-breakpoint
|
||||
DROP TRIGGER IF EXISTS `update_novel_stats_on_delete`;--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS `__migration_Novel` AS SELECT * FROM `Novel`;--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS `__migration_Chapter` AS SELECT * FROM `Chapter`;--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS `__migration_NovelCategory` AS SELECT * FROM `NovelCategory`;--> statement-breakpoint
|
||||
DROP TABLE IF EXISTS `__new_Novel`;--> statement-breakpoint
|
||||
CREATE TABLE `__new_Novel` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`pluginId` text NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`cover` text,
|
||||
`summary` text,
|
||||
`author` text,
|
||||
`artist` text,
|
||||
`status` text DEFAULT 'Unknown',
|
||||
`genres` text,
|
||||
`inLibrary` integer DEFAULT false,
|
||||
`isLocal` integer DEFAULT false,
|
||||
`totalPages` integer DEFAULT 0,
|
||||
`chaptersDownloaded` integer DEFAULT 0,
|
||||
`chaptersUnread` integer DEFAULT 0,
|
||||
`totalChapters` integer DEFAULT 0,
|
||||
`lastReadAt` text,
|
||||
`lastUpdatedAt` text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `__new_Novel` (
|
||||
`id`,
|
||||
`path`,
|
||||
`pluginId`,
|
||||
`name`,
|
||||
`cover`,
|
||||
`summary`,
|
||||
`author`,
|
||||
`artist`,
|
||||
`status`,
|
||||
`genres`,
|
||||
`inLibrary`,
|
||||
`isLocal`,
|
||||
`totalPages`,
|
||||
`chaptersDownloaded`,
|
||||
`chaptersUnread`,
|
||||
`totalChapters`,
|
||||
`lastReadAt`,
|
||||
`lastUpdatedAt`
|
||||
)
|
||||
SELECT
|
||||
`__migration_Novel`.`id`,
|
||||
`__migration_Novel`.`path`,
|
||||
`__migration_Novel`.`pluginId`,
|
||||
`__migration_Novel`.`name`,
|
||||
`__migration_Novel`.`cover`,
|
||||
`__migration_Novel`.`summary`,
|
||||
`__migration_Novel`.`author`,
|
||||
`__migration_Novel`.`artist`,
|
||||
`__migration_Novel`.`status`,
|
||||
`__migration_Novel`.`genres`,
|
||||
`__migration_Novel`.`inLibrary`,
|
||||
`__migration_Novel`.`isLocal`,
|
||||
`__migration_Novel`.`totalPages`,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM `__migration_Chapter`
|
||||
WHERE `__migration_Chapter`.`novelId` = `__migration_Novel`.`id`
|
||||
AND `__migration_Chapter`.`isDownloaded` = 1
|
||||
),
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM `__migration_Chapter`
|
||||
WHERE `__migration_Chapter`.`novelId` = `__migration_Novel`.`id`
|
||||
AND `__migration_Chapter`.`unread` = 1
|
||||
),
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM `__migration_Chapter`
|
||||
WHERE `__migration_Chapter`.`novelId` = `__migration_Novel`.`id`
|
||||
),
|
||||
(
|
||||
SELECT MAX(`__migration_Chapter`.`readTime`)
|
||||
FROM `__migration_Chapter`
|
||||
WHERE `__migration_Chapter`.`novelId` = `__migration_Novel`.`id`
|
||||
),
|
||||
(
|
||||
SELECT MAX(`__migration_Chapter`.`updatedTime`)
|
||||
FROM `__migration_Chapter`
|
||||
WHERE `__migration_Chapter`.`novelId` = `__migration_Novel`.`id`
|
||||
)
|
||||
FROM `__migration_Novel`;--> statement-breakpoint
|
||||
DELETE FROM `NovelCategory`;--> statement-breakpoint
|
||||
DELETE FROM `Chapter`;--> statement-breakpoint
|
||||
DROP TABLE IF EXISTS `Novel`;--> statement-breakpoint
|
||||
ALTER TABLE `__new_Novel` RENAME TO `Novel`;--> statement-breakpoint
|
||||
INSERT OR REPLACE INTO `Chapter` SELECT * FROM `__migration_Chapter`;--> statement-breakpoint
|
||||
INSERT OR REPLACE INTO `NovelCategory` SELECT * FROM `__migration_NovelCategory`;--> statement-breakpoint
|
||||
DROP TABLE `__migration_Novel`;--> statement-breakpoint
|
||||
DROP TABLE `__migration_Chapter`;--> statement-breakpoint
|
||||
DROP TABLE `__migration_NovelCategory`;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `novel_path_plugin_unique` ON `Novel` (`path`,`pluginId`);--> statement-breakpoint
|
||||
CREATE INDEX `NovelIndex` ON `Novel` (`pluginId`,`path`,`id`,`inLibrary`);
|
||||
@@ -3,11 +3,13 @@
|
||||
import m0000 from './20251222152612_past_mandrill/migration.sql';
|
||||
import m0001 from './20260612232322_normal_saracen/migration.sql';
|
||||
import m0002 from './20260719143427_long_moondragon/migration.sql';
|
||||
import m0003 from './20260727081855_calm_chimera/migration.sql';
|
||||
|
||||
export default {
|
||||
migrations: {
|
||||
"20251222152612_past_mandrill": m0000,
|
||||
"20260612232322_normal_saracen": m0001,
|
||||
"20260719143427_long_moondragon": m0002
|
||||
}
|
||||
}
|
||||
'20251222152612_past_mandrill': m0000,
|
||||
'20260612232322_normal_saracen': m0001,
|
||||
'20260719143427_long_moondragon': m0002,
|
||||
'20260727081855_calm_chimera': m0003,
|
||||
},
|
||||
};
|
||||
|
||||
+8
-2
@@ -1,3 +1,6 @@
|
||||
const { withRozenite } = require('@rozenite/metro');
|
||||
const { withRozeniteExpoAtlasPlugin } = require('@rozenite/expo-atlas-plugin');
|
||||
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
@@ -44,7 +47,7 @@ config.server.enhanceMiddleware = metroMiddleware => {
|
||||
response.setHeader(
|
||||
'Content-Type',
|
||||
readerAssetContentTypes[path.extname(assetPath)] ||
|
||||
'application/octet-stream',
|
||||
'application/octet-stream',
|
||||
);
|
||||
|
||||
if (request.method === 'HEAD') {
|
||||
@@ -55,4 +58,7 @@ config.server.enhanceMiddleware = metroMiddleware => {
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
module.exports = withRozenite(config, {
|
||||
enabled: process.env.WITH_ROZENITE === 'true',
|
||||
enhanceMetroConfig: metroConfig => withRozeniteExpoAtlasPlugin(metroConfig),
|
||||
});
|
||||
|
||||
+23
-3
@@ -25,8 +25,28 @@ interface BackgroundTaskDao {
|
||||
@Query("UPDATE background_tasks SET state = :state, updatedAt = :updatedAt WHERE id = :id AND state = 'running'")
|
||||
suspend fun finishRunning(id: String, state: String, updatedAt: Long)
|
||||
|
||||
@Query("UPDATE background_tasks SET state = :state, attempt = attempt + 1, updatedAt = :updatedAt WHERE id = :id")
|
||||
suspend fun markRunning(id: String, state: String, updatedAt: Long)
|
||||
@Query(
|
||||
"""
|
||||
UPDATE background_tasks
|
||||
SET state = :state, attempt = attempt + 1, updatedAt = :updatedAt
|
||||
WHERE id = :id
|
||||
AND state = 'queued'
|
||||
AND (
|
||||
type != 'DOWNLOAD_CHAPTER'
|
||||
OR (
|
||||
SELECT COUNT(*)
|
||||
FROM background_tasks
|
||||
WHERE type = 'DOWNLOAD_CHAPTER' AND state = 'running'
|
||||
) < :maxConcurrentDownloads
|
||||
)
|
||||
""",
|
||||
)
|
||||
suspend fun tryMarkRunning(
|
||||
id: String,
|
||||
state: String,
|
||||
updatedAt: Long,
|
||||
maxConcurrentDownloads: Int,
|
||||
): Int
|
||||
|
||||
@Query("UPDATE background_tasks SET progress = :progress, progressText = :progressText, updatedAt = :updatedAt WHERE id = :id")
|
||||
suspend fun updateProgress(id: String, progress: Double?, progressText: String?, updatedAt: Long)
|
||||
@@ -36,4 +56,4 @@ interface BackgroundTaskDao {
|
||||
|
||||
@Query("UPDATE background_tasks SET workId = :workId, updatedAt = :updatedAt WHERE id = :id")
|
||||
suspend fun assignWork(id: String, workId: String, updatedAt: Long)
|
||||
}
|
||||
}
|
||||
|
||||
+16
-3
@@ -2,10 +2,12 @@ package expo.modules.nativebackgroundtasks
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
@Database(entities = [BackgroundTaskEntity::class], version = 1, exportSchema = false)
|
||||
@Database(entities = [BackgroundTaskEntity::class], version = 2, exportSchema = false)
|
||||
abstract class BackgroundTaskDatabase : RoomDatabase() {
|
||||
abstract fun tasks(): BackgroundTaskDao
|
||||
|
||||
@@ -18,7 +20,18 @@ abstract class BackgroundTaskDatabase : RoomDatabase() {
|
||||
context.applicationContext,
|
||||
BackgroundTaskDatabase::class.java,
|
||||
"lnreader-background-tasks.db",
|
||||
).build().also { instance = it }
|
||||
).addMigrations(MIGRATION_1_2)
|
||||
.build()
|
||||
.also { instance = it }
|
||||
}
|
||||
|
||||
private val MIGRATION_1_2 = object : Migration(1, 2) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"ALTER TABLE background_tasks ADD COLUMN queueName TEXT NOT NULL " +
|
||||
"DEFAULT 'lnreader-background-task-queue'",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ data class BackgroundTaskEntity(
|
||||
val payload: String,
|
||||
val title: String,
|
||||
val description: String,
|
||||
val queueName: String,
|
||||
val state: String,
|
||||
val progress: Double?,
|
||||
val progressText: String?,
|
||||
@@ -29,4 +30,4 @@ object BackgroundTaskState {
|
||||
const val CANCELLED = "cancelled"
|
||||
|
||||
val active = listOf(QUEUED, RUNNING, PAUSED)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,7 +10,6 @@ import androidx.work.WorkManager
|
||||
import java.util.UUID
|
||||
|
||||
object BackgroundTaskScheduler {
|
||||
private const val QUEUE_NAME = "lnreader-background-task-queue"
|
||||
const val TASK_ID = "taskId"
|
||||
|
||||
suspend fun enqueue(context: Context, taskId: String): UUID {
|
||||
@@ -28,7 +27,7 @@ object BackgroundTaskScheduler {
|
||||
BackgroundTaskDatabase.get(context).tasks()
|
||||
.assignWork(taskId, request.id.toString(), System.currentTimeMillis())
|
||||
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||
QUEUE_NAME,
|
||||
task.queueName,
|
||||
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
||||
request,
|
||||
)
|
||||
@@ -52,6 +51,7 @@ object BackgroundTaskScheduler {
|
||||
payload = """{"name":"$LIBRARY_UPDATE_TASK_TYPE"}""",
|
||||
title = title,
|
||||
description = description,
|
||||
queueName = "lnreader-background-task:task:$LIBRARY_UPDATE_TASK_TYPE",
|
||||
state = BackgroundTaskState.QUEUED,
|
||||
progress = null,
|
||||
progressText = null,
|
||||
|
||||
+24
-4
@@ -21,7 +21,19 @@ class LNReaderTaskWorker(
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
dao.markRunning(taskId, BackgroundTaskState.RUNNING, System.currentTimeMillis())
|
||||
val claimed = dao.tryMarkRunning(
|
||||
taskId,
|
||||
BackgroundTaskState.RUNNING,
|
||||
System.currentTimeMillis(),
|
||||
MAX_CONCURRENT_DOWNLOADS,
|
||||
)
|
||||
if (claimed == 0) {
|
||||
return if (dao.get(taskId)?.state == BackgroundTaskState.QUEUED) {
|
||||
Result.retry()
|
||||
} else {
|
||||
Result.success()
|
||||
}
|
||||
}
|
||||
val runningTask = dao.get(taskId) ?: return Result.failure()
|
||||
setForeground(createForegroundInfo(runningTask))
|
||||
val execution = TaskExecutionRegistry.register(taskId)
|
||||
@@ -48,7 +60,9 @@ class LNReaderTaskWorker(
|
||||
return Result.success()
|
||||
}
|
||||
dao.finishRunning(taskId, BackgroundTaskState.SUCCEEDED, System.currentTimeMillis())
|
||||
dao.get(taskId)?.let { TaskNotificationFactory.update(applicationContext, it) }
|
||||
dao.get(taskId)?.let {
|
||||
TaskNotificationFactory.postTerminal(applicationContext, it)
|
||||
}
|
||||
Result.success()
|
||||
}
|
||||
is TaskExecutionResult.Failure -> {
|
||||
@@ -61,7 +75,9 @@ class LNReaderTaskWorker(
|
||||
Result.retry()
|
||||
} else {
|
||||
dao.updateState(taskId, BackgroundTaskState.FAILED, System.currentTimeMillis())
|
||||
dao.get(taskId)?.let { TaskNotificationFactory.update(applicationContext, it) }
|
||||
dao.get(taskId)?.let {
|
||||
TaskNotificationFactory.postTerminal(applicationContext, it)
|
||||
}
|
||||
Result.success()
|
||||
}
|
||||
}
|
||||
@@ -86,4 +102,8 @@ class LNReaderTaskWorker(
|
||||
ForegroundInfo(id, notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_CONCURRENT_DOWNLOADS = 3
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -27,7 +27,7 @@ class NativeBackgroundTasksModule : Module() {
|
||||
reactContextRef = null
|
||||
}
|
||||
|
||||
AsyncFunction("enqueue") { type: String, payload: String, title: String, description: String, allowsDuplicates: Boolean ->
|
||||
AsyncFunction("enqueue") { type: String, payload: String, title: String, description: String, allowsDuplicates: Boolean, queueName: String ->
|
||||
runBlocking(Dispatchers.IO) {
|
||||
if (!allowsDuplicates) {
|
||||
dao.getActiveByType(type)?.let { return@runBlocking it.id }
|
||||
@@ -39,6 +39,7 @@ class NativeBackgroundTasksModule : Module() {
|
||||
payload = payload,
|
||||
title = title,
|
||||
description = description,
|
||||
queueName = queueName,
|
||||
state = BackgroundTaskState.QUEUED,
|
||||
progress = null,
|
||||
progressText = null,
|
||||
@@ -130,10 +131,12 @@ class NativeBackgroundTasksModule : Module() {
|
||||
}
|
||||
}
|
||||
|
||||
AsyncFunction("complete") { taskId: String ->
|
||||
AsyncFunction("complete") { taskId: String, completionText: String ->
|
||||
runBlocking(Dispatchers.IO) {
|
||||
dao.updateCheckpoint(taskId, null, System.currentTimeMillis())
|
||||
dao.finishRunning(taskId, BackgroundTaskState.SUCCEEDED, System.currentTimeMillis())
|
||||
val now = System.currentTimeMillis()
|
||||
dao.updateCheckpoint(taskId, null, now)
|
||||
dao.updateProgress(taskId, null, completionText, now)
|
||||
dao.finishRunning(taskId, BackgroundTaskState.SUCCEEDED, now)
|
||||
TaskExecutionRegistry.complete(taskId, TaskExecutionResult.Success)
|
||||
}
|
||||
}
|
||||
|
||||
+30
-5
@@ -15,6 +15,7 @@ object TaskNotificationFactory {
|
||||
const val ACTION_RESUME = "expo.modules.nativebackgroundtasks.RESUME"
|
||||
const val ACTION_CANCEL = "expo.modules.nativebackgroundtasks.CANCEL"
|
||||
const val EXTRA_TASK_ID = "taskId"
|
||||
private const val TERMINAL_NOTIFICATION_MASK = 0x40000000
|
||||
|
||||
fun ensureChannel(context: Context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||
@@ -33,6 +34,9 @@ object TaskNotificationFactory {
|
||||
|
||||
fun notificationId(taskId: String): Int = taskId.hashCode().and(Int.MAX_VALUE).coerceAtLeast(1)
|
||||
|
||||
fun terminalNotificationId(taskId: String): Int =
|
||||
notificationId(taskId).xor(TERMINAL_NOTIFICATION_MASK).coerceAtLeast(1)
|
||||
|
||||
fun build(context: Context, task: BackgroundTaskEntity): Notification {
|
||||
ensureChannel(context)
|
||||
val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
||||
@@ -66,7 +70,13 @@ object TaskNotificationFactory {
|
||||
.setContentText(contentText)
|
||||
.setContentIntent(contentIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
||||
.setCategory(
|
||||
if (task.state in listOf(BackgroundTaskState.SUCCEEDED, BackgroundTaskState.FAILED)) {
|
||||
NotificationCompat.CATEGORY_STATUS
|
||||
} else {
|
||||
NotificationCompat.CATEGORY_PROGRESS
|
||||
},
|
||||
)
|
||||
.setOngoing(task.state == BackgroundTaskState.RUNNING || task.state == BackgroundTaskState.QUEUED)
|
||||
.setAutoCancel(task.state == BackgroundTaskState.SUCCEEDED || task.state == BackgroundTaskState.FAILED)
|
||||
.setOnlyAlertOnce(true)
|
||||
@@ -78,15 +88,22 @@ object TaskNotificationFactory {
|
||||
|
||||
val progress = task.progress
|
||||
if (task.state == BackgroundTaskState.SUCCEEDED) {
|
||||
builder.setContentText("Completed").setProgress(0, 0, false)
|
||||
builder.setContentText(contentText).setProgress(0, 0, false)
|
||||
} else if (task.state == BackgroundTaskState.FAILED) {
|
||||
builder.setContentText("Failed: $contentText").setProgress(0, 0, false)
|
||||
builder.setContentText(contentText).setProgress(0, 0, false)
|
||||
} else if (progress == null) {
|
||||
builder.setProgress(100, 0, true)
|
||||
} else {
|
||||
builder.setProgress(100, (progress.coerceIn(0.0, 1.0) * 100).toInt(), false)
|
||||
}
|
||||
|
||||
if (
|
||||
task.state in listOf(BackgroundTaskState.SUCCEEDED, BackgroundTaskState.FAILED) &&
|
||||
contentText.isNotBlank()
|
||||
) {
|
||||
builder.setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
|
||||
}
|
||||
|
||||
if (
|
||||
task.type == "UPDATE_LIBRARY" &&
|
||||
task.state in listOf(BackgroundTaskState.QUEUED, BackgroundTaskState.RUNNING, BackgroundTaskState.PAUSED) &&
|
||||
@@ -107,9 +124,17 @@ object TaskNotificationFactory {
|
||||
.notify(notificationId(task.id), build(context, task))
|
||||
}
|
||||
|
||||
fun dismiss(context: Context, taskId: String) {
|
||||
fun postTerminal(context: Context, task: BackgroundTaskEntity) {
|
||||
require(task.state in listOf(BackgroundTaskState.SUCCEEDED, BackgroundTaskState.FAILED))
|
||||
context.getSystemService(NotificationManager::class.java)
|
||||
.cancel(notificationId(taskId))
|
||||
.notify(terminalNotificationId(task.id), build(context, task))
|
||||
}
|
||||
|
||||
fun dismiss(context: Context, taskId: String) {
|
||||
context.getSystemService(NotificationManager::class.java).apply {
|
||||
cancel(notificationId(taskId))
|
||||
cancel(terminalNotificationId(taskId))
|
||||
}
|
||||
}
|
||||
|
||||
private fun actionIntent(
|
||||
|
||||
@@ -22,6 +22,7 @@ type NativeBackgroundTasksModule = {
|
||||
title: string,
|
||||
description: string,
|
||||
allowsDuplicates: boolean,
|
||||
queueName: string,
|
||||
): Promise<string>;
|
||||
getTasks(): Promise<NativeBackgroundTaskRecord[]>;
|
||||
pause(taskId: string): Promise<void>;
|
||||
@@ -33,7 +34,7 @@ type NativeBackgroundTasksModule = {
|
||||
progressText: string,
|
||||
): Promise<void>;
|
||||
updateCheckpoint(taskId: string, checkpoint: string): Promise<void>;
|
||||
complete(taskId: string): Promise<void>;
|
||||
complete(taskId: string, completionText: string): Promise<void>;
|
||||
fail(taskId: string, error: string, shouldRetry: boolean): Promise<void>;
|
||||
scheduleLibraryUpdates(
|
||||
intervalHours: number,
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lnreader",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev:android:release": "pnpm run generate:env:release && npx expo run:android --variant release",
|
||||
@@ -108,6 +108,9 @@
|
||||
"@babel/preset-env": "^7.29.7",
|
||||
"@babel/runtime": "^7.29.7",
|
||||
"@eslint/eslintrc": "^3.3.6",
|
||||
"@rozenite/expo-atlas-plugin": "^1.13.0",
|
||||
"@rozenite/metro": "^1.13.0",
|
||||
"@rozenite/sqlite-plugin": "^1.13.0",
|
||||
"@testing-library/react-native": "^13.3.3",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/color": "^4.2.1",
|
||||
|
||||
Generated
+1225
-621
File diff suppressed because it is too large
Load Diff
@@ -169,12 +169,14 @@ const releaseDate = args['release-date'] || formatUtcDate(new Date());
|
||||
const nodeEnv =
|
||||
args['node-env'] ||
|
||||
(buildType.toLowerCase().includes('release') ? 'production' : 'development');
|
||||
const rozeniteEnabled = nodeEnv !== 'production';
|
||||
|
||||
const generatedEnvContent = [
|
||||
formatEnvEntry('BUILD_TYPE', buildType),
|
||||
formatEnvEntry('GIT_HASH', gitHash),
|
||||
formatEnvEntry('RELEASE_DATE', releaseDate),
|
||||
formatEnvEntry('NODE_ENV', nodeEnv),
|
||||
formatEnvEntry('WITH_ROZENITE', rozeniteEnabled),
|
||||
formatEnvEntry('MYANIMELIST_CLIENT_ID', myanimelistClientId),
|
||||
formatEnvEntry('ANILIST_CLIENT_ID', anilistClientId),
|
||||
'',
|
||||
@@ -243,6 +245,7 @@ try {
|
||||
GIT_HASH: gitHash,
|
||||
RELEASE_DATE: releaseDate,
|
||||
NODE_ENV: nodeEnv,
|
||||
WITH_ROZENITE: rozeniteEnabled ? 'enabled' : 'disabled',
|
||||
MYANIMELIST_CLIENT_ID: myanimelistClientId
|
||||
? 'configured'
|
||||
: 'not configured',
|
||||
|
||||
@@ -53,7 +53,7 @@ function CustomBottomTabBar({
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: theme.surface2 || theme.surface,
|
||||
paddingBottom: insets?.bottom || 0,
|
||||
paddingBottom: 16 + (insets?.bottom || 0),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -148,7 +148,6 @@ const styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 6,
|
||||
paddingHorizontal: 4,
|
||||
position: 'relative',
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextStyle,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
import { Checkbox as PaperCheckbox } from 'react-native-paper';
|
||||
@@ -20,6 +21,8 @@ interface CheckboxProps {
|
||||
theme: ThemeColors;
|
||||
viewStyle?: StyleProp<ViewStyle>;
|
||||
labelStyle?: StyleProp<TextStyle>;
|
||||
description?: string;
|
||||
descriptionStyle?: StyleProp<TextStyle>;
|
||||
}
|
||||
|
||||
export const Checkbox: React.FC<CheckboxProps> = ({
|
||||
@@ -30,8 +33,17 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
||||
onPress,
|
||||
viewStyle,
|
||||
labelStyle,
|
||||
description,
|
||||
descriptionStyle,
|
||||
}) => (
|
||||
<Pressable
|
||||
accessibilityHint={description}
|
||||
accessibilityLabel={label}
|
||||
accessibilityRole="checkbox"
|
||||
accessibilityState={{
|
||||
checked: status === 'indeterminate' ? 'mixed' : status,
|
||||
disabled,
|
||||
}}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[styles.pressable, viewStyle]}
|
||||
onPress={onPress}
|
||||
@@ -53,9 +65,28 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
||||
uncheckedColor={theme.onSurfaceVariant}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Text style={[styles.defaultLabel, { color: theme.onSurface }, labelStyle]}>
|
||||
{label}
|
||||
</Text>
|
||||
<View style={styles.textContainer}>
|
||||
<Text
|
||||
style={[styles.defaultLabel, { color: theme.onSurface }, labelStyle]}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
{description ? (
|
||||
<Text
|
||||
style={[
|
||||
styles.description,
|
||||
{
|
||||
color: disabled
|
||||
? theme.onSurfaceDisabled
|
||||
: theme.onSurfaceVariant,
|
||||
},
|
||||
descriptionStyle,
|
||||
]}
|
||||
>
|
||||
{description}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
@@ -85,7 +116,13 @@ export const SortItem = ({ label, status, onPress, theme }: SortItemProps) => (
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
defaultLabel: {
|
||||
marginStart: 12,
|
||||
flexShrink: 1,
|
||||
},
|
||||
description: {
|
||||
flexShrink: 1,
|
||||
fontSize: 13,
|
||||
lineHeight: 18,
|
||||
marginTop: 2,
|
||||
},
|
||||
icon: {
|
||||
alignSelf: 'center',
|
||||
@@ -99,4 +136,9 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 6,
|
||||
},
|
||||
sortItem: { paddingVertical: 16, paddingStart: 64 },
|
||||
textContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
marginStart: 12,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { render, screen } from '@testing-library/react-native';
|
||||
|
||||
import { Checkbox } from '../Checkbox/Checkbox';
|
||||
import type { ThemeColors } from '../../theme/types';
|
||||
|
||||
const mockTheme = {
|
||||
onSurface: '#111111',
|
||||
onSurfaceDisabled: '#777777',
|
||||
onSurfaceVariant: '#555555',
|
||||
primary: '#6200ee',
|
||||
rippleColor: '#eeeeee',
|
||||
} as ThemeColors;
|
||||
|
||||
describe('Checkbox', () => {
|
||||
it('renders an accessible description below the label', () => {
|
||||
render(
|
||||
<Checkbox
|
||||
description="Include app preferences"
|
||||
label="Settings"
|
||||
onPress={() => {}}
|
||||
status
|
||||
theme={mockTheme}
|
||||
/>,
|
||||
);
|
||||
|
||||
const checkbox = screen.getByRole('checkbox', { name: 'Settings' });
|
||||
|
||||
expect(checkbox.props.accessibilityState).toEqual({
|
||||
checked: true,
|
||||
disabled: undefined,
|
||||
});
|
||||
expect(checkbox.props.accessibilityHint).toBe('Include app preferences');
|
||||
expect(screen.getByText('Include app preferences')).toBeOnTheScreen();
|
||||
});
|
||||
|
||||
it('centers the checkbox against the label and description block', () => {
|
||||
render(
|
||||
<Checkbox
|
||||
description="Include app preferences"
|
||||
label="Settings"
|
||||
status={false}
|
||||
theme={mockTheme}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole('checkbox', { name: 'Settings' })).toHaveStyle({
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@ import { schema } from '@database/schema';
|
||||
|
||||
import {
|
||||
getPendingMigrations,
|
||||
repairInterruptedNovelMigration,
|
||||
repairMigrationHistory,
|
||||
runDatabaseBootstrap,
|
||||
} from '@database/db';
|
||||
@@ -71,6 +72,32 @@ const MIGRATION_STATEMENTS = [
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS repository_url_unique ON Repository (url)`,
|
||||
];
|
||||
|
||||
const LEGACY_NOVEL_TABLE_STATEMENT = `CREATE TABLE IF NOT EXISTS Novel (
|
||||
id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
path text NOT NULL,
|
||||
pluginId text NOT NULL,
|
||||
name text NOT NULL,
|
||||
cover text,
|
||||
summary text,
|
||||
author text,
|
||||
artist text,
|
||||
status text DEFAULT 'Unknown',
|
||||
genres text,
|
||||
inLibrary integer DEFAULT false,
|
||||
isLocal integer DEFAULT false,
|
||||
totalPages integer DEFAULT 0
|
||||
)`;
|
||||
|
||||
const createSchema = (sqlite: DB, legacyNovel = false) => {
|
||||
for (const statement of MIGRATION_STATEMENTS) {
|
||||
sqlite.executeSync(
|
||||
legacyNovel && statement.startsWith('CREATE TABLE IF NOT EXISTS Novel (')
|
||||
? LEGACY_NOVEL_TABLE_STATEMENT
|
||||
: statement.trim(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const createExecutor = (sqlite: DB) => ({
|
||||
executeSync: (sql: string, params?: unknown[]) => {
|
||||
sqlite.executeSync(sql, params as any[]);
|
||||
@@ -131,9 +158,7 @@ describe('runDatabaseBootstrap', () => {
|
||||
(sqlite as any).executeAsync ??= sqlite.execute;
|
||||
(sqlite as any).executeRawAsync ??= sqlite.executeRaw;
|
||||
try {
|
||||
for (const statement of MIGRATION_STATEMENTS) {
|
||||
sqlite.executeSync(statement.trim());
|
||||
}
|
||||
createSchema(sqlite);
|
||||
|
||||
sqlite.executeSync('PRAGMA journal_mode = WAL');
|
||||
runDatabaseBootstrap(createExecutor(sqlite));
|
||||
@@ -174,9 +199,42 @@ describe('production migrations', () => {
|
||||
(sqlite as any).executeAsync ??= sqlite.execute;
|
||||
(sqlite as any).executeRawAsync ??= sqlite.executeRaw;
|
||||
try {
|
||||
for (const statement of MIGRATION_STATEMENTS) {
|
||||
sqlite.executeSync(statement.trim());
|
||||
}
|
||||
createSchema(sqlite);
|
||||
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Category (id, name, sort)
|
||||
VALUES (1, 'Existing category', 1)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Novel (id, path, pluginId, name, inLibrary)
|
||||
VALUES (1, '/existing', 'existing-plugin', 'Existing novel', 1)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Chapter (
|
||||
id,
|
||||
novelId,
|
||||
path,
|
||||
name,
|
||||
unread,
|
||||
isDownloaded,
|
||||
readTime,
|
||||
updatedTime
|
||||
)
|
||||
VALUES (
|
||||
1,
|
||||
1,
|
||||
'/existing/chapter-1',
|
||||
'Existing chapter',
|
||||
1,
|
||||
1,
|
||||
'2026-07-26T10:00:00.000Z',
|
||||
'2026-07-26T11:00:00.000Z'
|
||||
)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO NovelCategory (id, novelId, categoryId)
|
||||
VALUES (1, 1, 1)
|
||||
`);
|
||||
|
||||
const drizzleDb = drizzle(sqlite, { schema });
|
||||
await migrate(drizzleDb, getPendingMigrations(sqlite));
|
||||
@@ -194,20 +252,226 @@ describe('production migrations', () => {
|
||||
'Repository',
|
||||
]),
|
||||
);
|
||||
|
||||
expect(
|
||||
sqlite.executeSync(
|
||||
'SELECT id, name, chaptersDownloaded, chaptersUnread, totalChapters FROM Novel',
|
||||
).rows,
|
||||
).toEqual([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Existing novel',
|
||||
chaptersDownloaded: 1,
|
||||
chaptersUnread: 1,
|
||||
totalChapters: 1,
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
sqlite.executeSync('SELECT id, novelId, name FROM Chapter').rows,
|
||||
).toEqual([{ id: 1, novelId: 1, name: 'Existing chapter' }]);
|
||||
expect(
|
||||
sqlite.executeSync('SELECT id, novelId, categoryId FROM NovelCategory')
|
||||
.rows,
|
||||
).toEqual([{ id: 1, novelId: 1, categoryId: 1 }]);
|
||||
} finally {
|
||||
sqlite.close();
|
||||
}
|
||||
});
|
||||
|
||||
it('recovers when the scanlator column exists without a migration record', async () => {
|
||||
it('repairs a legacy Novel table that is missing counter columns', async () => {
|
||||
const sqlite = open({ name: ':memory:' });
|
||||
(sqlite as any).executeAsync ??= sqlite.execute;
|
||||
(sqlite as any).executeRawAsync ??= sqlite.executeRaw;
|
||||
try {
|
||||
for (const statement of MIGRATION_STATEMENTS) {
|
||||
sqlite.executeSync(statement.trim());
|
||||
}
|
||||
createSchema(sqlite, true);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Category (id, name, sort)
|
||||
VALUES (1, 'Existing category', 1)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Novel (id, path, pluginId, name, inLibrary)
|
||||
VALUES (1, '/legacy', 'legacy-plugin', 'Legacy novel', 1)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Chapter (
|
||||
id,
|
||||
novelId,
|
||||
path,
|
||||
name,
|
||||
unread,
|
||||
isDownloaded,
|
||||
readTime,
|
||||
updatedTime
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
1,
|
||||
1,
|
||||
'/legacy/chapter-1',
|
||||
'Chapter 1',
|
||||
0,
|
||||
1,
|
||||
'2026-07-25T10:00:00.000Z',
|
||||
'2026-07-25T11:00:00.000Z'
|
||||
),
|
||||
(
|
||||
2,
|
||||
1,
|
||||
'/legacy/chapter-2',
|
||||
'Chapter 2',
|
||||
1,
|
||||
0,
|
||||
NULL,
|
||||
'2026-07-26T11:00:00.000Z'
|
||||
)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO NovelCategory (id, novelId, categoryId)
|
||||
VALUES (1, 1, 1)
|
||||
`);
|
||||
|
||||
const drizzleDb = drizzle(sqlite, { schema });
|
||||
await migrate(drizzleDb, getPendingMigrations(sqlite));
|
||||
|
||||
expect(
|
||||
sqlite.executeSync(
|
||||
`SELECT
|
||||
id,
|
||||
chaptersDownloaded,
|
||||
chaptersUnread,
|
||||
totalChapters,
|
||||
lastReadAt,
|
||||
lastUpdatedAt
|
||||
FROM Novel`,
|
||||
).rows,
|
||||
).toEqual([
|
||||
{
|
||||
id: 1,
|
||||
chaptersDownloaded: 1,
|
||||
chaptersUnread: 1,
|
||||
totalChapters: 2,
|
||||
lastReadAt: '2026-07-25T10:00:00.000Z',
|
||||
lastUpdatedAt: '2026-07-26T11:00:00.000Z',
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
sqlite.executeSync('SELECT id FROM Chapter ORDER BY id').rows,
|
||||
).toEqual([{ id: 1 }, { id: 2 }]);
|
||||
expect(
|
||||
sqlite.executeSync('SELECT novelId, categoryId FROM NovelCategory')
|
||||
.rows,
|
||||
).toEqual([{ novelId: 1, categoryId: 1 }]);
|
||||
} finally {
|
||||
sqlite.close();
|
||||
}
|
||||
});
|
||||
|
||||
it('resumes after Novel was dropped during the previous repair migration', async () => {
|
||||
const sqlite = open({ name: ':memory:' });
|
||||
(sqlite as any).executeAsync ??= sqlite.execute;
|
||||
(sqlite as any).executeRawAsync ??= sqlite.executeRaw;
|
||||
try {
|
||||
createSchema(sqlite);
|
||||
sqlite.executeSync('ALTER TABLE Chapter ADD scanlator text');
|
||||
sqlite.executeSync('ALTER TABLE Chapter ADD timeSpent integer DEFAULT 0');
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Category (id, name, sort)
|
||||
VALUES (1, 'Existing category', 1)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Novel (id, path, pluginId, name, inLibrary)
|
||||
VALUES (1, '/interrupted', 'legacy-plugin', 'Interrupted novel', 1)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO Chapter (
|
||||
id,
|
||||
novelId,
|
||||
path,
|
||||
name,
|
||||
unread,
|
||||
isDownloaded,
|
||||
scanlator,
|
||||
timeSpent
|
||||
)
|
||||
VALUES (
|
||||
1,
|
||||
1,
|
||||
'/interrupted/chapter-1',
|
||||
'Chapter 1',
|
||||
1,
|
||||
1,
|
||||
'Group',
|
||||
12
|
||||
)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO NovelCategory (id, novelId, categoryId)
|
||||
VALUES (1, 1, 1)
|
||||
`);
|
||||
|
||||
sqlite.executeSync('CREATE TABLE __new_Novel AS SELECT * FROM Novel');
|
||||
sqlite.executeSync(
|
||||
'CREATE TABLE __migration_Chapter AS SELECT * FROM Chapter',
|
||||
);
|
||||
sqlite.executeSync(
|
||||
'CREATE TABLE __migration_NovelCategory AS SELECT * FROM NovelCategory',
|
||||
);
|
||||
sqlite.executeSync('DELETE FROM NovelCategory');
|
||||
sqlite.executeSync('DELETE FROM Chapter');
|
||||
sqlite.executeSync('DROP TABLE Novel');
|
||||
|
||||
repairInterruptedNovelMigration(sqlite);
|
||||
sqlite.executeSync(`
|
||||
CREATE TABLE __drizzle_migrations (
|
||||
id INTEGER PRIMARY KEY,
|
||||
hash text NOT NULL,
|
||||
created_at numeric,
|
||||
name text,
|
||||
applied_at text
|
||||
)
|
||||
`);
|
||||
sqlite.executeSync(`
|
||||
INSERT INTO __drizzle_migrations (hash, created_at, name)
|
||||
VALUES ('', 1766417172000, NULL)
|
||||
`);
|
||||
repairMigrationHistory(sqlite);
|
||||
|
||||
const drizzleDb = drizzle(sqlite, { schema });
|
||||
await migrate(drizzleDb, getPendingMigrations(sqlite));
|
||||
|
||||
expect(
|
||||
sqlite.executeSync(
|
||||
'SELECT id, name, chaptersDownloaded, chaptersUnread, totalChapters FROM Novel',
|
||||
).rows,
|
||||
).toEqual([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Interrupted novel',
|
||||
chaptersDownloaded: 1,
|
||||
chaptersUnread: 1,
|
||||
totalChapters: 1,
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
sqlite.executeSync('SELECT id, scanlator, timeSpent FROM Chapter').rows,
|
||||
).toEqual([{ id: 1, scanlator: 'Group', timeSpent: 12 }]);
|
||||
expect(
|
||||
sqlite.executeSync('SELECT novelId, categoryId FROM NovelCategory')
|
||||
.rows,
|
||||
).toEqual([{ novelId: 1, categoryId: 1 }]);
|
||||
} finally {
|
||||
sqlite.close();
|
||||
}
|
||||
});
|
||||
|
||||
it('recovers when Chapter columns exist without migration records', async () => {
|
||||
const sqlite = open({ name: ':memory:' });
|
||||
(sqlite as any).executeAsync ??= sqlite.execute;
|
||||
(sqlite as any).executeRawAsync ??= sqlite.executeRaw;
|
||||
try {
|
||||
createSchema(sqlite);
|
||||
sqlite.executeSync('ALTER TABLE Chapter ADD scanlator text');
|
||||
sqlite.executeSync('ALTER TABLE Chapter ADD timeSpent integer DEFAULT 0');
|
||||
sqlite.executeSync(`
|
||||
CREATE TABLE __drizzle_migrations (
|
||||
id INTEGER PRIMARY KEY,
|
||||
@@ -229,6 +493,11 @@ describe('production migrations', () => {
|
||||
"SELECT name FROM __drizzle_migrations WHERE name = '20260612232322_normal_saracen'",
|
||||
).rows,
|
||||
).toHaveLength(1);
|
||||
expect(
|
||||
sqlite.executeSync(
|
||||
"SELECT name FROM __drizzle_migrations WHERE name = '20260719143427_long_moondragon'",
|
||||
).rows,
|
||||
).toHaveLength(1);
|
||||
|
||||
const drizzleDb = drizzle(sqlite, { schema });
|
||||
await migrate(drizzleDb, getPendingMigrations(sqlite));
|
||||
@@ -237,6 +506,10 @@ describe('production migrations', () => {
|
||||
.executeRawSync('PRAGMA table_info(Chapter)')
|
||||
.filter(column => column[1] === 'scanlator');
|
||||
expect(scanlatorColumns).toHaveLength(1);
|
||||
const timeSpentColumns = sqlite
|
||||
.executeRawSync('PRAGMA table_info(Chapter)')
|
||||
.filter(column => column[1] === 'timeSpent');
|
||||
expect(timeSpentColumns).toHaveLength(1);
|
||||
|
||||
const appliedMigrations = sqlite.executeSync(
|
||||
'SELECT name FROM __drizzle_migrations ORDER BY created_at',
|
||||
@@ -244,7 +517,8 @@ describe('production migrations', () => {
|
||||
expect(appliedMigrations.map(row => row.name)).toEqual([
|
||||
'20251222152612_past_mandrill',
|
||||
'20260612232322_normal_saracen',
|
||||
'20260719143427_long_moondragon'
|
||||
'20260719143427_long_moondragon',
|
||||
'20260727081855_calm_chimera',
|
||||
]);
|
||||
} finally {
|
||||
sqlite.close();
|
||||
|
||||
+57
-5
@@ -30,6 +30,21 @@ const INITIAL_MIGRATION_NAME = '20251222152612_past_mandrill';
|
||||
const INITIAL_MIGRATION_CREATED_AT = 1766417172000;
|
||||
const SCANLATOR_MIGRATION_NAME = '20260612232322_normal_saracen';
|
||||
const SCANLATOR_MIGRATION_CREATED_AT = 1781306602000;
|
||||
const TIME_SPENT_MIGRATION_NAME = '20260719143427_long_moondragon';
|
||||
const TIME_SPENT_MIGRATION_CREATED_AT = 1784471667000;
|
||||
|
||||
const CHAPTER_COLUMN_MIGRATIONS = [
|
||||
{
|
||||
columnName: 'scanlator',
|
||||
migrationName: SCANLATOR_MIGRATION_NAME,
|
||||
createdAt: SCANLATOR_MIGRATION_CREATED_AT,
|
||||
},
|
||||
{
|
||||
columnName: 'timeSpent',
|
||||
migrationName: TIME_SPENT_MIGRATION_NAME,
|
||||
createdAt: TIME_SPENT_MIGRATION_CREATED_AT,
|
||||
},
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Raw SQLite database instance
|
||||
@@ -60,6 +75,39 @@ type MigrationExecutor = {
|
||||
executeSync: (sql: string) => unknown;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recovers the one interruption point where the previous repair migration
|
||||
* could have dropped Novel before renaming its populated replacement.
|
||||
*/
|
||||
export const repairInterruptedNovelMigration = (
|
||||
executor: MigrationExecutor,
|
||||
) => {
|
||||
const tableNames = new Set(
|
||||
executor
|
||||
.executeRawSync("SELECT name FROM sqlite_master WHERE type = 'table';")
|
||||
.map(row => row[0]),
|
||||
);
|
||||
const hasNovel = tableNames.has('Novel');
|
||||
const hasNovelSnapshot = tableNames.has('__migration_Novel');
|
||||
const hasNewNovel = tableNames.has('__new_Novel');
|
||||
const hasMigrationState =
|
||||
hasNovelSnapshot ||
|
||||
hasNewNovel ||
|
||||
tableNames.has('__migration_Chapter') ||
|
||||
tableNames.has('__migration_NovelCategory');
|
||||
|
||||
if (!hasMigrationState || hasNovel || hasNovelSnapshot) {
|
||||
return;
|
||||
}
|
||||
if (!hasNewNovel) {
|
||||
throw new Error(
|
||||
'Cannot recover interrupted Novel migration: no source table remains',
|
||||
);
|
||||
}
|
||||
|
||||
executor.executeSync("ALTER TABLE '__new_Novel' RENAME TO 'Novel';");
|
||||
};
|
||||
|
||||
/**
|
||||
* Repairs migration metadata created by older Drizzle versions and interrupted
|
||||
* migrations. SQLite cannot add a column conditionally, so an existing column
|
||||
@@ -94,17 +142,20 @@ export const repairMigrationHistory = (executor: MigrationExecutor) => {
|
||||
`);
|
||||
|
||||
const chapterColumns = executor.executeRawSync('PRAGMA table_info(Chapter);');
|
||||
const hasScanlator = chapterColumns.some(row => row[1] === 'scanlator');
|
||||
const chapterColumnNames = new Set(chapterColumns.map(row => row[1]));
|
||||
|
||||
if (hasScanlator) {
|
||||
for (const migration of CHAPTER_COLUMN_MIGRATIONS) {
|
||||
if (!chapterColumnNames.has(migration.columnName)) {
|
||||
continue;
|
||||
}
|
||||
executor.executeSync(`
|
||||
INSERT INTO __drizzle_migrations
|
||||
(hash, created_at, name, applied_at)
|
||||
SELECT '', ${SCANLATOR_MIGRATION_CREATED_AT},
|
||||
'${SCANLATOR_MIGRATION_NAME}', datetime('now')
|
||||
SELECT '', ${migration.createdAt},
|
||||
'${migration.migrationName}', datetime('now')
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM __drizzle_migrations
|
||||
WHERE name = '${SCANLATOR_MIGRATION_NAME}'
|
||||
WHERE name = '${migration.migrationName}'
|
||||
);
|
||||
`);
|
||||
}
|
||||
@@ -180,6 +231,7 @@ let initialization: Promise<void> | undefined;
|
||||
export const initializeDatabase = () => {
|
||||
if (!initialization) {
|
||||
setPragmas(_db);
|
||||
repairInterruptedNovelMigration(_db);
|
||||
repairMigrationHistory(_db);
|
||||
initialization = migrate(drizzleDb, getPendingMigrations(_db)).then(() => {
|
||||
runDatabaseBootstrap(_db);
|
||||
|
||||
@@ -48,6 +48,7 @@ export default function useDownload() {
|
||||
data: {
|
||||
novelName: novel.name,
|
||||
novelId: novel.id,
|
||||
pluginId: novel.pluginId,
|
||||
chapters: [{ chapterId: chapter.id, chapterName: chapter.name }],
|
||||
},
|
||||
});
|
||||
@@ -57,6 +58,7 @@ export default function useDownload() {
|
||||
data: {
|
||||
novelName: novel.name,
|
||||
novelId: novel.id,
|
||||
pluginId: novel.pluginId,
|
||||
chapters: chapters.map(chapter => ({
|
||||
chapterId: chapter.id,
|
||||
chapterName: chapter.name,
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "إدارة البيانات",
|
||||
"deleteReadChapters": "حذف الفصول المقروءة",
|
||||
"deleteReadChaptersDialogTitle": "حذف جميع الفصول التي تم قراءتها",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "استيراد EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "استيراد رواية",
|
||||
"importStaticFiles": "استيراد الملفات الثابتة",
|
||||
"novelInsertFailed": "فشل إدراج الرواية",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "وكيل المستخدم",
|
||||
"recreateDBIndexes": "إعادة إنشاء فهارس قاعدة البيانات",
|
||||
"recreateDBIndexesToast": "تمت إعادة إنشاء فهارس قاعدة البيانات",
|
||||
"recreateDBIndexesDialogTitle": "سيتم إعادة إنشاء جميع فهارس قاعدة البيانات.\nقد يستغرق هذا بعض الوقت.",
|
||||
"recreateDBIndexesDesc": "يعيد إنشاء فهارس قاعدة البيانات. قد يؤدي هذا إلى تحسين الأداء على الأجهزة الأبطأ."
|
||||
"recreateDBIndexesDesc": "يعيد إنشاء فهارس قاعدة البيانات. قد يؤدي هذا إلى تحسين الأداء على الأجهزة الأبطأ.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "مظهر",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "الافتراضي",
|
||||
"appTheme": "مظهر التطبيق",
|
||||
"darkTheme": "المظهر الداكن",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "إخفاء الخلفية",
|
||||
"lightTheme": "المظهر الفاتح",
|
||||
"navbar": "شريط التنقل",
|
||||
"novelInfo": "معلومات الرواية",
|
||||
"pureBlackDarkMode": "الأسود القاتم للوضع الداكن",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "إظهار التاريخ في شريط التنقل",
|
||||
"showUpdatesInTheNav": "إظهار التحديثات في شريط التنقل",
|
||||
"themeMode": "وضع السمة",
|
||||
@@ -75,7 +86,7 @@
|
||||
"backupCreated": "Backup created successfully",
|
||||
"backupRestored": "Backup restored successfully",
|
||||
"savingBackup": "Saving Backup",
|
||||
"categoriesRestored": "",
|
||||
"categoriesRestored": "Restored %{count} categories",
|
||||
"categoriesRestoredWithErrors": "Restored %{count} categories (%{failedCount} failed)",
|
||||
"categoryRestoreFailed": "Failed to restore category: %{categoryName} - %{error}",
|
||||
"categoryFileNotFound": "Category file not found in backup",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "متاح",
|
||||
"deletePluginMessage": "هل أنت متأكد أنك تريد إلغاء تثبيت %{name}؟",
|
||||
"discover": "استكشف",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "بحث عام",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "فشل التثبيت: %{name}",
|
||||
"installed": "تم التثبيت",
|
||||
"installedPlugin": "تم تثبيت %{name}",
|
||||
"installedPlugins": "الإضافات المثبتة",
|
||||
"language": "Language",
|
||||
"lastUsed": "اخر استخدام",
|
||||
"latest": "الاخير",
|
||||
"listEmpty": "تفعيل اللغات من الاعدادات",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "تم تثبيت %{name} في الأعلى",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "الإضافات المثبتة في الأعلى",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "تمت إزالته من المكتبة",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "البحث في المصادر",
|
||||
"searchResults": "نتائج البحث",
|
||||
"selectNovel": "اختر الرواية",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "تم إلغاء تثبيت %{name}",
|
||||
"unpinnedPlugin": "تم إلغاء التثبيت في الأعلى لـ %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "فشل التحديث",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "تم التحديث إلى %{version}",
|
||||
"settings": {
|
||||
"title": "إعدادات الإضافة",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "حول",
|
||||
"add": "إضافة",
|
||||
"all": "الكل",
|
||||
"back": "Back",
|
||||
"backup": "نسخة احتياطية",
|
||||
"cancel": "إلغاء",
|
||||
"categories": "تصنيفات",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "تصفية",
|
||||
"globally": "عالمياً",
|
||||
"install": "تثبيت",
|
||||
"imported": "Imported",
|
||||
"logout": "تسجيل الخروج",
|
||||
"name": "اسم",
|
||||
"newUpdateAvailable": "تحديث جديد متاح",
|
||||
"none": "None",
|
||||
"ok": "حسنآ",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "أعد المحاولة",
|
||||
"save": "حفظ",
|
||||
"saved": "Saved",
|
||||
"search": "بحث",
|
||||
"searchFor": "بحث عن",
|
||||
"searchResults": "نتائج البحث",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "فرز",
|
||||
"submit": "إرسال",
|
||||
"loading": "جارٍ التحميل...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "تحذير"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "تحديث",
|
||||
"share": "مشاركة",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "فتح في المتصفح",
|
||||
"clearCookies": "مسح ملفات تعريف الارتباط",
|
||||
"cookiesCleared": "تم مسح ملفات تعريف الارتباط",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "إما أن الفصل فارغ أو لم يتمكن التطبيق من كشطه",
|
||||
"chapterName": "الفصل: %{name}",
|
||||
"completed": "اكتمل التنزيل",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "جارٍ التنزيل",
|
||||
"downloadingNovel": "جارٍ تنزيل: %{name}",
|
||||
"downloadsLower": "التنزيلات",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(ترتيب تصاعدي)",
|
||||
"autoDownload": "التحميل التلقائي",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "حسب المصدر",
|
||||
"chapterSort": "الفرز الافتراضي للفصول",
|
||||
"desc": "(ترتيب تنازلي)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "قد يحسن الأداء على الأجهزة الأبطأ",
|
||||
"disableHapticFeedback": "تعطيل الاهتزاز",
|
||||
"disableHapticFeedbackDescription": "إيقاف الاهتزازات عند اللمس.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "وضع العرض",
|
||||
"downloadNewChapters": "تنزيل فصول جديدة",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "موقع EPUB",
|
||||
"epubLocationDescription": "المكان الذي تفتح فيه وتصدر إليه ملفات EPUB الخاصة بك.",
|
||||
"globalUpdate": "تحديث شامل",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "حجم الشبكة",
|
||||
"gridSizeDesc": "%{num} في كل صف",
|
||||
"itemsPerRow": "العناصر في كل صف",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "فرز الروايات",
|
||||
"refreshMetadata": "تحديث البيانات الوصفية تلقائياً",
|
||||
"refreshMetadataDescription": "التحقق من الغلاف الجديد والتفاصيل عند تحديث المكتبة",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "ترتيب الفرز",
|
||||
"updateLibrary": "تحديث المكتبة عند التشغيل",
|
||||
"updateLibraryDesc": "لا ينصح به للأجهزة الضعيفة",
|
||||
"updateTime": "إظهار وقت آخر تحديث",
|
||||
"useFAB": "استخدام الزر العائم (FAB) في المكتبة"
|
||||
"useFAB": "استخدام الزر العائم (FAB) في المكتبة",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "جميع المصادر",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "هل أنت متأكد؟ سيتم مسح كل السجل.",
|
||||
"deleted": "تم حذف السجل.",
|
||||
"nothingReadRecently": "لم يتم قراءة شيء مؤخراً",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "سجل البحث"
|
||||
},
|
||||
"library": "المكتبة",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "مكتبتك فارغة. أضف سلاسل إلى مكتبتك من التصفح.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "استيراد EPUB",
|
||||
"openRandom": "فتح مدخل عشوائي",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "محفوظ",
|
||||
"downloaded": "منزل",
|
||||
"unread": "غير مقروء"
|
||||
"unread": "غير مقروء",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "حسب اسم الفصل",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "فشل تصدير EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "تم تصدير %{chapters} فصلاً بنجاح كملف EPUB",
|
||||
"noDownloadedChapters": "لم يتم العثور على فصول محملة. يرجى تحميل الفصول قبل التصدير.",
|
||||
"noNovelSelected": "لم يتم اختيار رواية للتصدير"
|
||||
"noNovelSelected": "لم يتم اختيار رواية للتصدير",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "اسم الفصل",
|
||||
"chapterNumber": "رقم الفصل",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "أدخل اسم فصل صحيح",
|
||||
"validChapterNumber": "أدخل رَقْم فصل صحيح"
|
||||
},
|
||||
"jumpToChapter": "انتقل إلى الفصل",
|
||||
"openChapter": "فتح الفصل"
|
||||
"openChapter": "فتح الفصل",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "نقل",
|
||||
"noSummary": "لا يوجد ملخص",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "تحديد النص",
|
||||
"autoscroll": "تمرير تلقائي",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "قراءة بيونية",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "النقر للتمرير",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "اللون",
|
||||
"display": "Display",
|
||||
"fontStyle": "نمط الخط",
|
||||
"fullscreen": "ملء الشاشة",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "ارتفاع السطر",
|
||||
"navigation": "Navigation",
|
||||
"padding": "تباعد",
|
||||
"pageReader": "قراءة بصفحات (تجريبي)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "إزالة المسافات الزائدة",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "مقدار التمرير (افتراضياً طول الشاشة)",
|
||||
"showBatteryAndTime": "البطارية والوقت",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "تقدم القراءة",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "السحب بين الفصول",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "محاذاة النص",
|
||||
"textSize": "حجم الخط",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "السحب لفتح الدرج",
|
||||
"verticalSeekbar": "شريط تمرير رأسي",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "إبقاء الشاشة مضاءة",
|
||||
"volumeButtonsScroll": "التمرير بأزرار الصوت"
|
||||
"volumeButtonsScroll": "التمرير بأزرار الصوت",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "التمرير للأسفل",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "انتهى",
|
||||
"nextChapter": "التالي: %{name}",
|
||||
"noNextChapter": "لا يوجد فصل تالي",
|
||||
"noPreviousChapter": "لا يوجد فصل سابق"
|
||||
"noPreviousChapter": "لا يوجد فصل سابق",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "فاصل التمرير (ثواني)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "لون النص",
|
||||
"textColorModal": "لون النص",
|
||||
"title": "القارئ",
|
||||
"verticalSeekbarDesc": "استخدم شريط تمرير رأسي"
|
||||
"verticalSeekbarDesc": "استخدم شريط تمرير رأسي",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "لم يتم العثور على أي نتائج"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "الإحصائيات",
|
||||
"titlesInLibrary": "العناوين في المكتبة",
|
||||
"totalChapters": "إجمالي الفصول",
|
||||
"unreadChapters": "الفصول غير المقروءة"
|
||||
"unreadChapters": "الفصول غير المقروءة",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "التتبع",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "تسجيل الخروج من %{name}؟",
|
||||
"revalidate": "إعادة التحقق",
|
||||
"services": "الخدمات"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "جاري استيراد EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "جاري تحديث المكتبة",
|
||||
"DRIVE_BACKUP": "نسخ احتياطي لجوجل درايف",
|
||||
"DRIVE_RESTORE": "استعادة من جوجل درايف",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "استعادة من نسخة احتياطية محلية",
|
||||
"MIGRATE_NOVEL": "جاري نقل الرواية",
|
||||
"DOWNLOAD_CHAPTER": "جاري تنزيل الفصل"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "আবিষ্কাৰ কৰক",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "বিশ্বব্যাপী সন্ধান",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "শেষত ব্যৱহৃত",
|
||||
"latest": "সাম্প্ৰতিক",
|
||||
"listEmpty": "ছেটিংছৰ পৰা ভাষা সক্ৰিয় কৰক",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "পুথিভঁৰালৰ পৰা আঁতৰ কৰা হৈছে",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "উৎসত সন্ধান কৰক",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "যোগ কৰক",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "বাতিল",
|
||||
"categories": "শ্ৰেণীবিভাজন",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "বিশ্বব্যাপী",
|
||||
"install": "স্থাপন",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "নাম",
|
||||
"newUpdateAvailable": "নতুন আপডেট উপলব্ধ",
|
||||
"none": "None",
|
||||
"ok": "হ’ব",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "পুনৰ চেষ্টা কৰক",
|
||||
"save": "সংৰক্ষণ",
|
||||
"saved": "Saved",
|
||||
"search": "সন্ধান",
|
||||
"searchFor": "সন্ধান কৰক",
|
||||
"searchResults": "সন্ধান ফলাফল",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "জমা দিয়ক",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "ডাউনলোডসমূহ",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "সকলো উৎস",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "আপুনি নিশ্চিত? সকলো ইতিহাস হেৰাই যাব।",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "ইতিহাসত সন্ধান কৰক"
|
||||
},
|
||||
"library": "পুথিভঁৰাল",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "আপোনাৰ পুথিভঁৰাল খালী। ‘ব্ৰাউজ’ৰ পৰা শৃংখলা যোগ কৰক।",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "অধ্যায়ৰ নাম",
|
||||
"chapterNumber": "অধ্যায় নম্বৰ",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "বৈধ অধ্যায়ৰ নাম দিন",
|
||||
"validChapterNumber": "বৈধ অধ্যায় নম্বৰ দিন"
|
||||
},
|
||||
"jumpToChapter": "অধ্যায়লৈ যাওক",
|
||||
"openChapter": "অধ্যায় খুলক"
|
||||
"openChapter": "অধ্যায় খুলক",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "স্থানান্তৰিত কৰক",
|
||||
"noSummary": "কোনো সংক্ষিপ্তসাৰ নাই",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "ৰঙ",
|
||||
"display": "Display",
|
||||
"fontStyle": "ফণ্টৰ শৈলী",
|
||||
"fullscreen": "সম্পূৰ্ণপর্দা",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "স্ক্ৰল পৰিমাণ (প্ৰদৰ্শন উচ্চতা অনুযায়ী)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "আখৰৰ আকাৰ",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "তললৈ স্ক্ৰল কৰক",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "শেষ",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "পৰবর্তী অধ্যায় নাই",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "কোনো ফলাফল পোৱা নাযায়"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "পৰিসংখ্যা",
|
||||
"titlesInLibrary": "গ্ৰন্থাগাৰত শিৰোনামসমূহ",
|
||||
"totalChapters": "মুঠ অধ্যায়সমূহ",
|
||||
"unreadChapters": "নপঢ়া অধ্যায়সমূহ"
|
||||
"unreadChapters": "নপঢ়া অধ্যায়সমূহ",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Objevit",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Globální vyhledávání",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Naposledy použité",
|
||||
"latest": "Poslední",
|
||||
"listEmpty": "Povolit jazyky z nastavení",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Odstraněno z knihovny",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Zdroje hledání",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Přidat",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Zrušit",
|
||||
"categories": "Kategorie",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globálně",
|
||||
"install": "Instalovat",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Jméno",
|
||||
"newUpdateAvailable": "Nová aktualizace k dispozici",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Opakovat",
|
||||
"save": "Uložit",
|
||||
"saved": "Saved",
|
||||
"search": "Hledat",
|
||||
"searchFor": "Hledat",
|
||||
"searchResults": "Výsledky hledání",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Odeslat",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "stažené",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "všechny zdroje",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Jste si jistí? Celá historie bude stracena.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Historie hledání"
|
||||
},
|
||||
"library": "Knihovna",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Vaše knihovna je prázdná. Přidejte sérii do knihovny z procházet.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Název kapitoly",
|
||||
"chapterNumber": "Číslo kapitoly",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Zadejte platný název kapitoly",
|
||||
"validChapterNumber": "Zadejte platné číslo kapitoly"
|
||||
},
|
||||
"jumpToChapter": "Přeskočit na kapitolu",
|
||||
"openChapter": "Otevřít kapitolu"
|
||||
"openChapter": "Otevřít kapitolu",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrovat",
|
||||
"noSummary": "Žádné shrnutí",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Barva",
|
||||
"display": "Display",
|
||||
"fontStyle": "Styl písma",
|
||||
"fullscreen": "Celá obrazovka",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Vzdálenost posunu (jako výchozí velikost výška obrazovky)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Velikost textu",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Přejít na konec",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Dokončeno",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Nejsou žádné další kapitoly",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Nebyly nalezeny žádné výsledky"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistiky",
|
||||
"titlesInLibrary": "Názvy v knihovně",
|
||||
"totalChapters": "Kapitol dohromady",
|
||||
"unreadChapters": "Nepřečtené kapitoly"
|
||||
"unreadChapters": "Nepřečtené kapitoly",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Gelesene Kapitel löschen",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Standard",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Entdecke",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Globale Suche",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Zuletzt genutzt",
|
||||
"latest": "Aktuell",
|
||||
"listEmpty": "Sprachen in Einstellungen aktivieren",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Aus der Bibliothek entfernt",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Quellen durchsuchen",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Hinzufügen",
|
||||
"all": "Alle",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Abbrechen",
|
||||
"categories": "Kategorien",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "global",
|
||||
"install": "Installieren",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "Neues Update verfügbar",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Erneut versuchen",
|
||||
"save": "Sichern",
|
||||
"saved": "Saved",
|
||||
"search": "Suchen",
|
||||
"searchFor": "Suche nach",
|
||||
"searchResults": "Suchergebnisse",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sortieren",
|
||||
"submit": "Bestätigen",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "Downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Aufsteigend)",
|
||||
"autoDownload": "Automatisch herunterladen",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Nach Quelle",
|
||||
"chapterSort": "Standard Kapitel-Sortierung",
|
||||
"desc": "(Absteigend)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Haptisches Feedback deaktivieren",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Anzeigemodus",
|
||||
"downloadNewChapters": "Neue Kapitel herunterladen",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Speicherort",
|
||||
"epubLocationDescription": "Der Speicherort, an dem Sie Ihre EPUB Dateien öffnen und exportieren.",
|
||||
"globalUpdate": "Globale Aktualisierung",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Bücher pro Reihe",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Bücher Sortierung",
|
||||
"refreshMetadata": "Metadaten automatisch aktualisieren",
|
||||
"refreshMetadataDescription": "Suche nach neuen Cover und Details beim Aktualisieren der Bibliothek",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Bibliothek beim Starten aktualisieren",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Zeige den Zeitpunkt der letzten Aktualisierung",
|
||||
"useFAB": "FAB in der Bibliothek verwenden"
|
||||
"useFAB": "FAB in der Bibliothek verwenden",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "Alle Quellen",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Bist du sicher? Der gesamte Verlauf geht verloren.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Suchverlauf"
|
||||
},
|
||||
"library": "Bibliothek",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Deine Bibliothek ist leer. Füge Serien über Browse zu deiner Bibliothek hinzu.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Kapitelname",
|
||||
"chapterNumber": "Kapitelnummer",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Geben Sie einen gültigen Kapitelnamen ein",
|
||||
"validChapterNumber": "Geben Sie eine gültige Kapitelnummer ein"
|
||||
},
|
||||
"jumpToChapter": "Zum Kapitel springen",
|
||||
"openChapter": "Kapitel öffnen"
|
||||
"openChapter": "Kapitel öffnen",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrieren",
|
||||
"noSummary": "Keine Beschreibung",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Farbe",
|
||||
"display": "Display",
|
||||
"fontStyle": "Schriftart",
|
||||
"fullscreen": "Vollbildmodus",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Höhe des Bildlaufs (standardmäßig Bildschirmhöhe)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Schriftgröße",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Zum Ende springen",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Beendet",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Es gibt kein weiteres Kapitel",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Textfarbe",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Keine Ergebnisse gefunden"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistiken",
|
||||
"titlesInLibrary": "Bücher in der Bibliothek",
|
||||
"totalChapters": "Gesamte Kapitel",
|
||||
"unreadChapters": "Ungelesene Kapitel"
|
||||
"unreadChapters": "Ungelesene Kapitel",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Τελευταία χρήση",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Ενεργοποιήστε γλώσσες από τις ρυθμίσεις",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Καταργήθηκε από τη βιβλιοθήκη",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Αναζήτηση πηγών",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Προσθήκη",
|
||||
"all": "Όλα",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Ακύρωση",
|
||||
"categories": "Κατηγορίες",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Εγκατάσταση",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Όνομα",
|
||||
"newUpdateAvailable": "Νέα ενημέρωση διαθέσιμη",
|
||||
"none": "None",
|
||||
"ok": "Οκ",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Επανάληψη",
|
||||
"save": "Αποθήκευση",
|
||||
"saved": "Saved",
|
||||
"search": "Αναζήτηση",
|
||||
"searchFor": "Αναζήτηση για",
|
||||
"searchResults": "Αποτελέσματα αναζήτησης",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Υποβολή",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Είστε σίγουροι; Όλο το ιστορικό θα χαθεί.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Βιβλιοθήκη",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Η βιβλιοθήκη σας είναι άδεια. Προσθέστε σειρές στη βιβλιοθήκη σας από την Περιήγηση.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Χρώμα",
|
||||
"display": "Display",
|
||||
"fontStyle": "Στυλ γραμματοσειράς",
|
||||
"fullscreen": "Πλήρης Οθόνη",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Μέγεθος κειμένου",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Κύλιση προς τα κάτω",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Δεν υπάρχει επόμενο κεφάλαιο",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +84,24 @@
|
||||
"backupScreen": {
|
||||
"backupName": "Backup name",
|
||||
"backupCreated": "Backup created successfully",
|
||||
"backupCreatedWithWarnings": "Backup created with warnings: %{warnings}",
|
||||
"backupRestored": "Backup restored successfully",
|
||||
"backupRestoredSelectedWithWarnings": "Backup restored with warnings: %{warnings}",
|
||||
"backupRestoredSummary": {
|
||||
"one": "Restored %{count} novel",
|
||||
"other": "Restored %{count} novels"
|
||||
},
|
||||
"backupRestoredWithWarnings": {
|
||||
"one": "Restored %{count} novel with warnings: %{warnings}",
|
||||
"other": "Restored %{count} novels with warnings: %{warnings}"
|
||||
},
|
||||
"savingBackup": "Saving Backup",
|
||||
"categoriesRestored": "Restored %{count} categories",
|
||||
"categoriesRestoredWithErrors": "Restored %{count} categories (%{failedCount} failed)",
|
||||
"categoriesRestoreFailedSummary": {
|
||||
"one": "%{count} category failed",
|
||||
"other": "%{count} categories failed"
|
||||
},
|
||||
"categoryRestoreFailed": "Failed to restore category: %{categoryName} - %{error}",
|
||||
"categoryFileNotFound": "Category file not found in backup",
|
||||
"categoryFileReadFailed": "Failed to read category file: %{error}",
|
||||
@@ -100,14 +114,34 @@
|
||||
"failed": "Backup failed",
|
||||
"novelsRestored": "Restored %{count} novels",
|
||||
"novelsRestoredWithErrors": "Restored %{count} novels (%{failedCount} failed)",
|
||||
"novelsBackupFailedSummary": {
|
||||
"one": "%{count} novel failed",
|
||||
"other": "%{count} novels failed"
|
||||
},
|
||||
"novelsRestoreFailedSummary": {
|
||||
"one": "%{count} novel failed",
|
||||
"other": "%{count} novels failed"
|
||||
},
|
||||
"novelBackupFailed": "Failed to backup novel: %{novelName} - %{error}",
|
||||
"novelRestoreFailed": "Failed to restore novel: %{novelName} - %{error}",
|
||||
"novelDirectoryNotFound": "Novel directory not found in backup",
|
||||
"novelDirectoryReadFailed": "Failed to read novel directory: %{error}",
|
||||
"restoringCategories": "Restoring Categories",
|
||||
"restoringCategoriesProgress": "Restoring categories (%{current}/%{total})",
|
||||
"restoringNovels": "Restoring Novels",
|
||||
"restoringNovelsProgress": "Restoring novels (%{current}/%{total})",
|
||||
"restoringSettings": "Restoring Settings",
|
||||
"missingPluginsAfterRestore": "Missing plugins: %{plugins}",
|
||||
"sectionsRestoreFailedSummary": {
|
||||
"one": "%{count} backup section failed",
|
||||
"other": "%{count} backup sections failed"
|
||||
},
|
||||
"sectionsBackupFailedSummary": {
|
||||
"one": "%{count} backup section failed",
|
||||
"other": "%{count} backup sections failed"
|
||||
},
|
||||
"settingsRestored": "Settings restored",
|
||||
"settingsRestoreFailedSummary": "settings failed",
|
||||
"settingsFileNotFound": "Settings file not found in backup",
|
||||
"settingsRestoreFailed": "Failed to restore settings: %{error}",
|
||||
"settingsFileWriteFailed": "Failed to write settings file: %{error}",
|
||||
@@ -124,7 +158,21 @@
|
||||
"invalidBackupFolder": "Invalid backup folder",
|
||||
"localBackup": "Local Backup",
|
||||
"noBackupFound": "No backup found",
|
||||
"options": {
|
||||
"title": "Backup contents",
|
||||
"description": "Choose what to include in this backup.",
|
||||
"selectAll": "Select all",
|
||||
"library": "Library data",
|
||||
"libraryDescription": "Novels, chapter lists, reading progress, bookmarks, and categories.",
|
||||
"settings": "Settings",
|
||||
"settingsDescription": "App, reader, and update preferences.",
|
||||
"plugins": "Plugins",
|
||||
"pluginsDescription": "Installed source plugin files.",
|
||||
"downloadedFiles": "Downloaded chapters and covers",
|
||||
"downloadedFilesDescription": "Downloaded chapter content and saved novel covers. This may be large."
|
||||
},
|
||||
"preparingData": "Preparing Data",
|
||||
"preparingSelectedFiles": "Preparing selected files",
|
||||
"remote": {
|
||||
"backup": "Self Host Backup",
|
||||
"host": "Host",
|
||||
@@ -136,9 +184,11 @@
|
||||
"restoreLargeBackupsWarning": "Restoring large backups may freeze the app until restoring is finished",
|
||||
"restorinBackup": "Restoring backup",
|
||||
"restoringData": "Restoring Data",
|
||||
"restoringSelectedFiles": "Restoring selected files",
|
||||
"selfHost": "Self Host",
|
||||
"selfHostDesc": "Backup to your server",
|
||||
"uploadingData": "Uploading Data",
|
||||
"uploadingSelectedFiles": "Uploading selected files",
|
||||
"uploadingDownloadedFiles": "Uploading Downloaded Files"
|
||||
},
|
||||
"browse": "Browse",
|
||||
@@ -686,7 +736,10 @@
|
||||
"LOCAL_BACKUP": "Local Backup",
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter",
|
||||
"taskQueued": "%{task} queued",
|
||||
"taskCompleted": "Completed",
|
||||
"taskFailed": "Failed: %{error}"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Administración de datos",
|
||||
"deleteReadChapters": "Eliminar capítulos leídos",
|
||||
"deleteReadChaptersDialogTitle": "Todos los capítulos marcados como leídos serán borrados.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Importar EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Importar novela",
|
||||
"importStaticFiles": "Importar archivos estáticos",
|
||||
"novelInsertFailed": "inserción de novela fallida",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Usar FAB en lugar del botón",
|
||||
"userAgent": "Agente de Usuario",
|
||||
"recreateDBIndexes": "Recrear índices de la Base de Datos",
|
||||
"recreateDBIndexesToast": "Índices de la Base de Datos Recreados",
|
||||
"recreateDBIndexesDialogTitle": "Todos los índices de la base de datos serán Recreados. Esto puede tomar un tiempo.",
|
||||
"recreateDBIndexesDesc": "Recrea los índices de la Base de Datos. Esto puede mejorar el rendimiento en dispositivos más lentos."
|
||||
"recreateDBIndexesDesc": "Recrea los índices de la Base de Datos. Esto puede mejorar el rendimiento en dispositivos más lentos.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Apariencia",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "Tema de la aplicación",
|
||||
"darkTheme": "Tema Oscuro",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Ocultar fondo",
|
||||
"lightTheme": "Tema Claro",
|
||||
"navbar": "Barra de navegación",
|
||||
"novelInfo": "Información de la Novela",
|
||||
"pureBlackDarkMode": "Modo negro puro",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Mostrar historial en el navegador",
|
||||
"showUpdatesInTheNav": "Mostrar actualizaciones en el navegador",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Disponible",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Explorar",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Búsqueda global",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Instalación fallida: %{name}",
|
||||
"installed": "Instalado",
|
||||
"installedPlugin": "%{name} Instalado",
|
||||
"installedPlugins": "Complementos instalados",
|
||||
"language": "Language",
|
||||
"lastUsed": "Última usada",
|
||||
"latest": "Últimos",
|
||||
"listEmpty": "Habilitar idiomas desde la configuración",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "¿Migrar %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "La novela ya está en la biblioteca",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Seleccionar fuente",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Eliminar de la biblioteca",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Buscar fuente",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Seleccionar novela",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Desinstalado %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Actualización fallida",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Actualizado a %{version}",
|
||||
"settings": {
|
||||
"title": "Ajustes del plugin",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "Acerca de",
|
||||
"add": "Añadir",
|
||||
"all": "Todos",
|
||||
"back": "Back",
|
||||
"backup": "Copia de seguridad",
|
||||
"cancel": "Cancelar",
|
||||
"categories": "Categorías",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filtrar",
|
||||
"globally": "globalmente",
|
||||
"install": "Instalar",
|
||||
"imported": "Imported",
|
||||
"logout": "Cerrar sesión",
|
||||
"name": "Nombre",
|
||||
"newUpdateAvailable": "Nueva actualización disponible",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pausa",
|
||||
"preparing": "Preparando",
|
||||
"remove": "Eliminar",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Reanudar",
|
||||
"retry": "Reintentar",
|
||||
"save": "Guardar",
|
||||
"saved": "Saved",
|
||||
"search": "Buscar",
|
||||
"searchFor": "Buscar por",
|
||||
"searchResults": "Resultados de la búsqueda",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Ordenar",
|
||||
"submit": "Enviar",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "descargas",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascendente)",
|
||||
"autoDownload": "Descarga automática",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Por fuente",
|
||||
"chapterSort": "Orden de capítulo por defecto",
|
||||
"desc": "(Descendente)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Deshabilitar la respuesta háptica",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Modo de visualización",
|
||||
"downloadNewChapters": "Descargar nuevos capítulos",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "Ubicación EPUB",
|
||||
"epubLocationDescription": "El lugar donde se abren y exportan sus archivos EPUB.",
|
||||
"globalUpdate": "Actualización global",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Elementos por fila",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Ordenar novela",
|
||||
"refreshMetadata": "Actualizar automáticamente los metadatos",
|
||||
"refreshMetadataDescription": "Buscar nueva portada y detalles al actualizar la biblioteca",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Actualizar biblioteca al iniciar",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Mostrar la última actualización",
|
||||
"useFAB": "Usar FAB en la biblioteca"
|
||||
"useFAB": "Usar FAB en la biblioteca",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "Todas las fuentes",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "¿Estás seguro? Todo el historial se perderá.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Historial de búsqueda"
|
||||
},
|
||||
"library": "Biblioteca",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Tu biblioteca está vacía. Añade series a tu biblioteca desde el navegador.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Nombre del capítulo",
|
||||
"chapterNumber": "Número del capítulo",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Introduzca un nombre de capítulo válido",
|
||||
"validChapterNumber": "Introduzca un número de capítulo válido"
|
||||
},
|
||||
"jumpToChapter": "Saltar al capítulo",
|
||||
"openChapter": "Abrir Capítulo"
|
||||
"openChapter": "Abrir Capítulo",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrar",
|
||||
"noSummary": "Sin resumen",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Estilo de fuente",
|
||||
"fullscreen": "Pantalla completa",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Cantidad de desplazamiento (alto de la pantalla de forma predeterminada)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Tamaño del texto",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Desplazarse hasta abajo",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finalizado",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "No hay próximo capítulo",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Color del texto",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Lector",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No se han encontrado resultados"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Estadísticas",
|
||||
"titlesInLibrary": "Títulos en biblioteca",
|
||||
"totalChapters": "Capítulos totales",
|
||||
"unreadChapters": "Capítulos no leídos"
|
||||
"unreadChapters": "Capítulos no leídos",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"cachedNovelsDeletedToast": "Romans en cache supprimés",
|
||||
"chapterInsertFailed": "Insertion de chapitre échoué",
|
||||
"clearCachedNovels": "Vider les romans en cache",
|
||||
"clearCachedNovelsDesc": "",
|
||||
"clearCachedNovelsDesc": "Delete cached novels which not in your library",
|
||||
"clearDatabaseWarning": "Les progrès et les chapitres lus et téléchargés hors de la bibliothèque, seront perdus.",
|
||||
"clearUpdatesMessage": "Mises à jour effacées.",
|
||||
"clearUpdatesTab": "Effacer l'onglet Mises à jour",
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Gestion de données",
|
||||
"deleteReadChapters": "Supprimer les chapitres lus",
|
||||
"deleteReadChaptersDialogTitle": "Tous les chapitres marqués comme lus seront supprimés.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Importer EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Importer un roman",
|
||||
"importStaticFiles": "Importer les fichiers statiques",
|
||||
"novelInsertFailed": "Insertion du roman échouée",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "Agent utilisateur",
|
||||
"recreateDBIndexes": "Récréer les index de la base de donnée",
|
||||
"recreateDBIndexesToast": "Index de la base de données recréés",
|
||||
"recreateDBIndexesDialogTitle": "Tous les index de la base de données seront recréés.\nCela peut prendre un certain temps.",
|
||||
"recreateDBIndexesDesc": "Recrée les index de la base de données. Cela peut améliorer les performances sur les appareils plus lents."
|
||||
"recreateDBIndexesDesc": "Recrée les index de la base de données. Cela peut améliorer les performances sur les appareils plus lents.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Apparence",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Par défaut",
|
||||
"appTheme": "Thème",
|
||||
"darkTheme": "Sombre",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Masquer l'arrière-plan",
|
||||
"lightTheme": "Clair",
|
||||
"navbar": "Barre de navigation",
|
||||
"novelInfo": "Informations sur le roman",
|
||||
"pureBlackDarkMode": "Mode noir pur",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Afficher l'historique dans la navigation",
|
||||
"showUpdatesInTheNav": "Afficher les mises à jour dans la navigation",
|
||||
"themeMode": "Thème",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Disponible",
|
||||
"deletePluginMessage": "Êtes-vous sûr de vouloir désinstaller %{name}?",
|
||||
"discover": "Découvrir",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Recherche globale",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "L'installation a échoué: %{name}",
|
||||
"installed": "Installé",
|
||||
"installedPlugin": "Installé %{name}",
|
||||
"installedPlugins": "Plugins installés",
|
||||
"language": "Language",
|
||||
"lastUsed": "Dernière utilisation",
|
||||
"latest": "Dernier",
|
||||
"listEmpty": "Activer les langues à partir des paramètres",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Sélectionner la source",
|
||||
"selectSourceDesc": "Sélectionnez une source à partir de laquelle migrer"
|
||||
"selectSourceDesc": "Sélectionnez une source à partir de laquelle migrer",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Épinglé %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Plugins épinglés",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Supprimé de la bibliothèque",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Rechercher des sources",
|
||||
"searchResults": "Résultats de la recherche",
|
||||
"selectNovel": "Sélectionnez un roman",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Désinstallé %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Mise à jour échouée",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Mis à jour %{version}",
|
||||
"settings": {
|
||||
"title": "Paramètres des plugins",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "À propos",
|
||||
"add": "Ajouter",
|
||||
"all": "Tout",
|
||||
"back": "Back",
|
||||
"backup": "Sauvegarde",
|
||||
"cancel": "Annuler",
|
||||
"categories": "Catégories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filtre",
|
||||
"globally": "globalement",
|
||||
"install": "Installer",
|
||||
"imported": "Imported",
|
||||
"logout": "Se déconnecter",
|
||||
"name": "Nom",
|
||||
"newUpdateAvailable": "Nouvelle mise à jour disponible",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Mettre en pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Retirer",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Réessayer",
|
||||
"save": "Sauvegarder",
|
||||
"saved": "Saved",
|
||||
"search": "Recherchez",
|
||||
"searchFor": "Rechercher",
|
||||
"searchResults": "Résultats de la recherche",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Trier",
|
||||
"submit": "Soumettre",
|
||||
"loading": "Chargement ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Actualiser",
|
||||
"share": "Partager",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Ouvrir dans le navigateur",
|
||||
"clearCookies": "Effacer les cookies",
|
||||
"cookiesCleared": "Cookies effacés",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapitre : %{name}",
|
||||
"completed": "Téléchargement terminé",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Téléchargement",
|
||||
"downloadingNovel": "Téléchargement : %{name}",
|
||||
"downloadsLower": "télécharger",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascendant)",
|
||||
"autoDownload": "Téléchargement automatique",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Par Source",
|
||||
"chapterSort": "Tri des chapitres par défaut",
|
||||
"desc": "(Descendant)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Désactiver le retour haptique",
|
||||
"disableHapticFeedbackDescription": "Désactiver les vibrations pour les interactions tactiles.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Mode d'affichage",
|
||||
"downloadNewChapters": "Télécharger les nouveaux chapitres",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "Localisation EPUB",
|
||||
"epubLocationDescription": "L'endroit où vous ouvrez et exportez vos fichiers EPUB.",
|
||||
"globalUpdate": "Mise à jour globale",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Taille de la grille",
|
||||
"gridSizeDesc": "%{num} par ligne",
|
||||
"itemsPerRow": "Élément par ligne",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Trier les romans",
|
||||
"refreshMetadata": "Rafraîchir automatiquement les métadonnées",
|
||||
"refreshMetadataDescription": "Vérifier la nouvelle couverture et les détails lors de la mise à jour de la bibliothèque",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Ordre de tri",
|
||||
"updateLibrary": "Mettre à jour la bibliothèque au lancement",
|
||||
"updateLibraryDesc": "Non recommandé pour les appareils ????",
|
||||
"updateTime": "Afficher la date de dernière mise à jour",
|
||||
"useFAB": "Utiliser FAB dans la bibliothèque"
|
||||
"useFAB": "Utiliser FAB dans la bibliothèque",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "toutes les sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Êtes-vous sûr? Tout l'historique sera perdu.",
|
||||
"deleted": "Historique supprimé.",
|
||||
"nothingReadRecently": "Rien lu récemment",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Historique des recherches"
|
||||
},
|
||||
"library": "Bibliothèque",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Votre bibliothèque est vide. Ajouter des séries à votre bibliothèque à partir de Parcourir",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Importer un EPUB",
|
||||
"openRandom": "Ouvrir une série au hasard",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Signet",
|
||||
"downloaded": "Téléchargé",
|
||||
"unread": "Non lu"
|
||||
"unread": "Non lu",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "Par nom de chapitre",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Le JS personnalisé peut ne pas être pris en charge par tous les lecteurs EPUB",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "Fin du chapitre",
|
||||
"export": "Export",
|
||||
"exportAll": "Exporter tous les chapitres",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Inclure le CSS personnalisé",
|
||||
"includeCustomJS": "Inclure le JS personnalisé",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Veuillez saisir un numéro de chapitre valide",
|
||||
"selectFolder": "Sélectionnez le dossier de destination pour le fichier EPUB",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Impossible d'exporter l'EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Couverture sauvegardée",
|
||||
"coverNotSaved": "Couverture non sauvegardée",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Nom du Chapitre",
|
||||
"chapterNumber": "Numéro du chapitre",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Entrez un nom de chapitre valide",
|
||||
"validChapterNumber": "Entrez un numéro de chapitre valide"
|
||||
},
|
||||
"jumpToChapter": "Aller au chapitre",
|
||||
"openChapter": "Ouvrir le chapitre"
|
||||
"openChapter": "Ouvrir le chapitre",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrer",
|
||||
"noSummary": "Aucun résumé",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Sélection de texte",
|
||||
"autoscroll": "Défilement automatique",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Couleur",
|
||||
"display": "Display",
|
||||
"fontStyle": "Style de police",
|
||||
"fullscreen": "Plein écran",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Hauteur de la ligne",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Marge intérieure",
|
||||
"pageReader": "Lecture paginée (Expérimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Défilement du montant (hauteur de l'écran par défaut)",
|
||||
"showBatteryAndTime": "Batterie et Heure",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Progression de la lecture",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Balayer entre les chapitres",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Alignement du texte",
|
||||
"textSize": "Taille du texte",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Bouton de volume pour défilé"
|
||||
"volumeButtonsScroll": "Bouton de volume pour défilé",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Défiler jusqu'en bas",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Terminé",
|
||||
"nextChapter": "Suivant: %{name}",
|
||||
"noNextChapter": "Il n'y a pas de prochain chapitre",
|
||||
"noPreviousChapter": "Il n'y a pas de chapitre précédent"
|
||||
"noPreviousChapter": "Il n'y a pas de chapitre précédent",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Couleur du texte",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Lecteur",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Aucun résultat trouvé"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistiques",
|
||||
"titlesInLibrary": "Titres dans la bibliothèque",
|
||||
"totalChapters": "Nombre total de chapitres",
|
||||
"unreadChapters": "Chapitres non lus"
|
||||
"unreadChapters": "Chapitres non lus",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Suivi",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Se déconnecter de %{name} ?",
|
||||
"revalidate": "Revalider",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "ניהול מידע",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "יבוא רומן",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "תצוגה",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "ערכת נושא כהה",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "ערכת נושא בהירה",
|
||||
"navbar": "סרגל הניווט",
|
||||
"novelInfo": "מידע על הרומן",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "הראה היסטוריה בסרגל הניווט",
|
||||
"showUpdatesInTheNav": "הראה עדכונים בסרגל הניווט",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Olvasott fejezetek törlése",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Felfedezés",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Globális keresés",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Utoljára használt",
|
||||
"latest": "Legújabb",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Eltávolítva a könyvtárból",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Források keresése",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Hozzáadás",
|
||||
"all": "Összes",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Mégse",
|
||||
"categories": "Kategóriák",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Szűrő",
|
||||
"globally": "globálisan",
|
||||
"install": "Telepítés",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Név",
|
||||
"newUpdateAvailable": "Új frissítés érhető el",
|
||||
"none": "None",
|
||||
"ok": "OK",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Újrapróbálkozás",
|
||||
"save": "Mentés",
|
||||
"saved": "Saved",
|
||||
"search": "Keresés",
|
||||
"searchFor": "Keresés a következőre",
|
||||
"searchResults": "Keresési eredmények",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Rendezés",
|
||||
"submit": "Küldés",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "letöltések",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Növekvő)",
|
||||
"autoDownload": "Automatikus letöltés",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Forrás szerint",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Csökkenő)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Haptikus visszajelzés kikapcsolása",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Megjelenítési mód",
|
||||
"downloadNewChapters": "Új fejezetek letöltése",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Globális frissítés",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Soronkénti elemek",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Metaadatok automatikus frissítése",
|
||||
"refreshMetadataDescription": "Új borító és leírás keresése a könyvtár frissítésekor",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Könyvtár frissítése indításkor",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Utolsó frissítés idejének mutatása",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "összes forrás",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Biztos vagy benne? Minden előzmény törlődni fog.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Keresési előzmények"
|
||||
},
|
||||
"library": "Könyvtár",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "A könyvtárad üres. Adj sorozatokat a könyvtáradhoz a Böngészés menüben.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Fejezet címe",
|
||||
"chapterNumber": "Fejezet száma",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Adj meg egy létező fejezetcímet",
|
||||
"validChapterNumber": "Adj meg egy létező fejezetszámot"
|
||||
},
|
||||
"jumpToChapter": "Fejezethez ugrás",
|
||||
"openChapter": "Fejezet megnyitása"
|
||||
"openChapter": "Fejezet megnyitása",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Áttelepítés",
|
||||
"noSummary": "Nincs összefoglaló",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Szín",
|
||||
"display": "Display",
|
||||
"fontStyle": "Betűtípus",
|
||||
"fullscreen": "Teljes képernyő",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Görgetés mértéke (alapértelmezetten a képernyő magassága)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Betűméret",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Végére ugrás",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Befejezett",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Nincs következő fejezet",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Betűszín",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Olvasó",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Nincs találat"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statisztikák",
|
||||
"titlesInLibrary": "Címek a könyvtárban",
|
||||
"totalChapters": "Összes fejezetek száma",
|
||||
"unreadChapters": "Olvasatlan fejezetek"
|
||||
"unreadChapters": "Olvasatlan fejezetek",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Elimina capitoli letti",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Scopri",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Ricerca globale",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Ultima usata",
|
||||
"latest": "Ultimi",
|
||||
"listEmpty": "Abilita le lingue dalle impostazioni",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Rimosso dalla libreria",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Cerca fonti",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Aggiungi",
|
||||
"all": "Tutte",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Annulla",
|
||||
"categories": "Categorie",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filtra",
|
||||
"globally": "globale",
|
||||
"install": "Installa",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Nome",
|
||||
"newUpdateAvailable": "Nuovo aggiornamento disponibile",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Riprova",
|
||||
"save": "Salva",
|
||||
"saved": "Saved",
|
||||
"search": "Cerca",
|
||||
"searchFor": "Cerca per",
|
||||
"searchResults": "Risultati della ricerca",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Ordina",
|
||||
"submit": "Invia",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "Scaricamenti",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Crescente)",
|
||||
"autoDownload": "Scarica automaticamente",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Per fonte",
|
||||
"chapterSort": "Ordinamento predefinito dei capitoli",
|
||||
"desc": "(Decrescente)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disattiva vibrazione",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Modalità di visualizzazione",
|
||||
"downloadNewChapters": "Scarica nuovi capitoli",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "Posizione EPUB",
|
||||
"epubLocationDescription": "Il posto dove apri ed esporti i tuoi file EPUB.",
|
||||
"globalUpdate": "Aggiornamento globale",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Elementi per riga",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Ordine novel",
|
||||
"refreshMetadata": "Aggiorna automaticamente i metadati",
|
||||
"refreshMetadataDescription": "Controlla nuove copertine e dettagli durante l'aggiornamento della libreria",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Aggiorna la libreria all'avvio",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Mostra l'orario dell'ultimo aggiornamento",
|
||||
"useFAB": "Usa FAB nella libreria"
|
||||
"useFAB": "Usa FAB nella libreria",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "Tutte le fonti",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Sei sicuro? Tutta la cronologia sarà persa.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Cerca nella cronologia"
|
||||
},
|
||||
"library": "Libreria",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "La tua libreria è vuota. Aggiungi delle serie alla tua libreria da Esplora.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Nome Capitolo",
|
||||
"chapterNumber": "Numero del capitolo",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Inserisci un nome di capitolo valido",
|
||||
"validChapterNumber": "Inserisci un numero di capitolo valido"
|
||||
},
|
||||
"jumpToChapter": "Vai al Capitolo",
|
||||
"openChapter": "Apri Capitolo"
|
||||
"openChapter": "Apri Capitolo",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migra",
|
||||
"noSummary": "Nessuna trama",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Colore",
|
||||
"display": "Display",
|
||||
"fontStyle": "Stile del font",
|
||||
"fullscreen": "Schermo Intero",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Quantità di scorrimento (altezza schermo di default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Dimensione del testo",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scorri in fondo",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finito",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Non c'è un capitolo successivo",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Colore del testo",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Lettore",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Nessun risultato trovato"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistiche",
|
||||
"titlesInLibrary": "Titoli nella libreria",
|
||||
"totalChapters": "Totale capitoli",
|
||||
"unreadChapters": "Capitoli non letti"
|
||||
"unreadChapters": "Capitoli non letti",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "グローバル検索",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "設定から言語を有効にする",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "ライブラリから削除",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "ソースを検索",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "追加",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "キャンセル",
|
||||
"categories": "カテゴリー",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "世界的に",
|
||||
"install": "インストール",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "名前",
|
||||
"newUpdateAvailable": "新しいアップデートが見つかりました",
|
||||
"none": "None",
|
||||
"ok": "わかりました",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "保存",
|
||||
"saved": "Saved",
|
||||
"search": "検索",
|
||||
"searchFor": "検索する",
|
||||
"searchResults": "検索結果",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "本当によろしいですか?すべての履歴は失われます。",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "閲覧履歴"
|
||||
},
|
||||
"library": "ライブラリ",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "移行",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "フォントスタイル",
|
||||
"fullscreen": "全画面",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "文字サイズ",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "次の章はありません",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"aboutScreen": {
|
||||
"website": "",
|
||||
"website": "Website",
|
||||
"discord": "Discord",
|
||||
"github": "Github",
|
||||
"helpTranslate": "Help translate",
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Verwijder gelezen hoofdstukken",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Ontdek",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Globaal zoeken",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Laatst gebruikt",
|
||||
"latest": "Recentst",
|
||||
"listEmpty": "Schakel talen in via instellingen",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Verwijderd uit bibliotheek",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Zoek bronnen",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Voeg toe",
|
||||
"all": "Alle",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Annuleren",
|
||||
"categories": "Categorieën",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globaal",
|
||||
"install": "Installeer",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Naam",
|
||||
"newUpdateAvailable": "Nieuwe update beschikbaar",
|
||||
"none": "None",
|
||||
"ok": "Oké",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Opslaan",
|
||||
"saved": "Saved",
|
||||
"search": "Zoeken",
|
||||
"searchFor": "Zoek naar",
|
||||
"searchResults": "Zoekresultaten",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sorteer",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "alle bronnen",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Weet je het zeker? Alle geschiedenis zal verloren gaan.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Zoek geschiedenis"
|
||||
},
|
||||
"library": "Bibliotheek",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Je bibliotheek is leeg. Voeg series toe aan je bibliotheek vanuit Bladeren.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migreer",
|
||||
"noSummary": "Geen samenvatting",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Kleur",
|
||||
"display": "Display",
|
||||
"fontStyle": "Lettertype",
|
||||
"fullscreen": "Volledig scherm",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Tekstgrootte",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Voltooid",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Er is geen volgend hoofdstuk",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Tekstkleur",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Lezer",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Geen resultaten gevonden"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistieken",
|
||||
"titlesInLibrary": "Titels in bibliotheek",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Ongelezen hoofdstukken"
|
||||
"unreadChapters": "Ongelezen hoofdstukken",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "ଯୋଡ଼ନ୍ତୁ",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "ବର୍ଗ",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "ନାମ",
|
||||
"newUpdateAvailable": "ନୂଆ ଅଦ୍ୟତନ ଉପଲବ୍ଧ",
|
||||
"none": "None",
|
||||
"ok": "ଠିକ୍ ଅଛି",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "ପୁନଃ ଚେଷ୍ଟା କରିବା",
|
||||
"save": "ସଞ୍ଚୟ କରିବା",
|
||||
"saved": "Saved",
|
||||
"search": "ସନ୍ଧାନ",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Manejo de informação",
|
||||
"deleteReadChapters": "Excluir capítulos lidos",
|
||||
"deleteReadChaptersDialogTitle": "Você tem certeza? Todos os capítulos marcados como lidos serão excluídos.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Importar EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Importar livro",
|
||||
"importStaticFiles": "Importar arquivo estático",
|
||||
"novelInsertFailed": "falha ao inserir livro",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Utilize FAV invez do botão",
|
||||
"userAgent": "Agente usuário",
|
||||
"recreateDBIndexes": "Recriar índices do BD",
|
||||
"recreateDBIndexesToast": "Índices do BD foi recriado",
|
||||
"recreateDBIndexesDialogTitle": "Todos os índices do BD vai ser Recriado.\nIsso pode demorar um pouco.",
|
||||
"recreateDBIndexesDesc": "Recrie os índices do BD. Isso pode melhorar o desempenho em dispositivos mais lentos."
|
||||
"recreateDBIndexesDesc": "Recrie os índices do BD. Isso pode melhorar o desempenho em dispositivos mais lentos.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Aparência",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Padrão",
|
||||
"appTheme": "Tema do aplicativo",
|
||||
"darkTheme": "Tema escuro",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Esconder fundo",
|
||||
"lightTheme": "Tema claro",
|
||||
"navbar": "Barra de navegação",
|
||||
"novelInfo": "Informação do livro",
|
||||
"pureBlackDarkMode": "Modo escuridão",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Mostrar histórico no navegador",
|
||||
"showUpdatesInTheNav": "Mostrar novidades no navegador",
|
||||
"themeMode": "Aparência",
|
||||
@@ -66,7 +77,7 @@
|
||||
"teal": "Ciano",
|
||||
"turquoise": "Turquesa",
|
||||
"yotsuba": "Japonês",
|
||||
"catppuccin": "",
|
||||
"catppuccin": "Catppuccin",
|
||||
"yinyang": "Yin & Yang"
|
||||
}
|
||||
},
|
||||
@@ -104,11 +115,11 @@
|
||||
"drive": {
|
||||
"backup": "Salvar no Drive",
|
||||
"backupInterruped": "Backup do Drive interrompido",
|
||||
"googleDriveBackup": "",
|
||||
"restore": "",
|
||||
"googleDriveBackup": "Google Drive Backup",
|
||||
"restore": "Drive Restore",
|
||||
"restoreInterruped": "Restauração do Drive interrompida"
|
||||
},
|
||||
"googeDrive": "",
|
||||
"googeDrive": "Googe Drive",
|
||||
"googeDriveDesc": "Fazer backup no Google Drive",
|
||||
"invalidBackupFolder": "Pasta de backup inválida",
|
||||
"localBackup": "Backup local",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Disponível",
|
||||
"deletePluginMessage": "Tem certeza de que deseja desinstalar o %{name}?",
|
||||
"discover": "Descubra",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Pesquisa global",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "A instalação falhou: %{name}",
|
||||
"installed": "Instalado",
|
||||
"installedPlugin": "%{name} Instalado",
|
||||
"installedPlugins": "Extensões Instalado",
|
||||
"language": "Language",
|
||||
"lastUsed": "Usado por último",
|
||||
"latest": "Mais recentes",
|
||||
"listEmpty": "Habilitar idiomas a partir das configurações",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrar %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel já está na biblioteca",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Selecionar fonte",
|
||||
"selectSourceDesc": "Selecione uma fonte para migrar"
|
||||
"selectSourceDesc": "Selecione uma fonte para migrar",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Sua biblioteca não tem nenhuma novel desta fonte",
|
||||
"pinnedPlugin": "%{name} fixado",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Extensões fixadas",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removido da biblioteca",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Pesquisar nas fontes",
|
||||
"searchResults": "Resultados da pesquisa",
|
||||
"selectNovel": "Selecionar novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "%{name} desinstalada",
|
||||
"unpinnedPlugin": "%{name} desfixada",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Atualização falhou",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Atualizado para %{version}",
|
||||
"settings": {
|
||||
"title": "Configurações da extensão",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "Sobre",
|
||||
"add": "Adicionar",
|
||||
"all": "Todos",
|
||||
"back": "Back",
|
||||
"backup": "Salvo",
|
||||
"cancel": "Cancelar",
|
||||
"categories": "Categorias",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filtro",
|
||||
"globally": "globalmente",
|
||||
"install": "Instalar",
|
||||
"imported": "Imported",
|
||||
"logout": "Desconectar",
|
||||
"name": "Nome",
|
||||
"newUpdateAvailable": "Nova atualização disponível",
|
||||
"none": "None",
|
||||
"ok": "Confirmar",
|
||||
"close": "Close",
|
||||
"pause": "Pausar",
|
||||
"preparing": "Preparando",
|
||||
"remove": "Remover",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Continuar",
|
||||
"retry": "Tente novamente",
|
||||
"save": "Salvar",
|
||||
"saved": "Saved",
|
||||
"search": "Pesquisar",
|
||||
"searchFor": "Pesquisar por",
|
||||
"searchResults": "Resultados da busca",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Ordenar por",
|
||||
"submit": "Aplicar",
|
||||
"loading": "Carregando...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Aviso"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Rever",
|
||||
"share": "Compartilhar",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Abrir na internet",
|
||||
"clearCookies": "Limpar dados temporários",
|
||||
"cookiesCleared": "Dados temporários limpos",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Capítulo: %{name}",
|
||||
"completed": "Transferência completa",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Transferindo",
|
||||
"downloadingNovel": "Transferindo: %{name}",
|
||||
"downloadsLower": "baixados",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Crescente)",
|
||||
"autoDownload": "Download automático",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Por fonte",
|
||||
"chapterSort": "Ordem padrão dos capítulos",
|
||||
"desc": "(Decrescente)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "Pode aumentar o desempenho em dispositivos mais lentos",
|
||||
"disableHapticFeedback": "Desativar o feedback tátil",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Modo de exibição",
|
||||
"downloadNewChapters": "Baixar novos capítulos",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "Localização do EPUB",
|
||||
"epubLocationDescription": "O local onde você abre e exporta seus arquivos EPUB.",
|
||||
"globalUpdate": "Atualização global",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Itens por linha",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Ordenar Novel",
|
||||
"refreshMetadata": "Atualizar os metadados automaticamente",
|
||||
"refreshMetadataDescription": "Verificar por novas capas e detalhes durante a atualização da biblioteca",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Ordenar",
|
||||
"updateLibrary": "Atualizar biblioteca ao iniciar",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Mostrar horário da última atualização",
|
||||
"useFAB": "Usar Botões flutuantes na Biblioteca"
|
||||
"useFAB": "Usar Botões flutuantes na Biblioteca",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "todas as fontes",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Você tem certeza? Todo o histórico será perdido.",
|
||||
"deleted": "Histórico deletado",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Histórico de pesquisa"
|
||||
},
|
||||
"library": "Biblioteca",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Sua biblioteca está vazia. Adicione séries à sua biblioteca pelo Navegador.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Importar EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Favoritado",
|
||||
"downloaded": "Transferido",
|
||||
"unread": "Não lido"
|
||||
"unread": "Não lido",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "Por nome do capítulo",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "Finalizar capítulo",
|
||||
"export": "Export",
|
||||
"exportAll": "Exportar todos os capítulos",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Incluir CSS personalizado",
|
||||
"includeCustomJS": "Incluir JS personalizado",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Por favor, insira um número válido de capítulos",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Iniciar capítulo",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Nome do capítulo",
|
||||
"chapterNumber": "Número do Capítulo",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Insira um nome de capítulo válido",
|
||||
"validChapterNumber": "Insira um número de capítulo válido"
|
||||
},
|
||||
"jumpToChapter": "Pular para o Capítulo",
|
||||
"openChapter": "Abrir Capítulo"
|
||||
"openChapter": "Abrir Capítulo",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrar",
|
||||
"noSummary": "Nenhum resumo",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Cor",
|
||||
"display": "Display",
|
||||
"fontStyle": "Estilo da fonte",
|
||||
"fullscreen": "Tela cheia",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Valor da rolagem (Padrão: altura da tela)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Tamanho do texto",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Rolar para o final",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finalizado",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "Não há próximo capítulo",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Cor do Texto",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Leitor",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Nenhum resultado encontrado"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Estatísticas",
|
||||
"titlesInLibrary": "Títulos na biblioteca",
|
||||
"totalChapters": "Total de capítulos",
|
||||
"unreadChapters": "Capítulos não lidos"
|
||||
"unreadChapters": "Capítulos não lidos",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Управление данными",
|
||||
"deleteReadChapters": "Удалять прочитанные главы",
|
||||
"deleteReadChaptersDialogTitle": "Вы уверены? Все главы, помеченные как прочитанные, будут удалены.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Импорт EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Импорт новеллы",
|
||||
"importStaticFiles": "Импорт файлов статики",
|
||||
"novelInsertFailed": "ошибка вставки главы",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Использовать плавающую кнопку действия вместо основной кнопки",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Пересоздать индексы базы данных",
|
||||
"recreateDBIndexesToast": "Индексы базы данных пересозданы",
|
||||
"recreateDBIndexesDialogTitle": "Все индексы базы данных будут пересозданы.\nЭто может занять некоторое время.",
|
||||
"recreateDBIndexesDesc": "Пересоздаёт индексы базы данных. Это может улучшить производительность на слабых устройствах."
|
||||
"recreateDBIndexesDesc": "Пересоздаёт индексы базы данных. Это может улучшить производительность на слабых устройствах.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Внешний вид",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "По умолчанию",
|
||||
"appTheme": "Тема приложения",
|
||||
"darkTheme": "Тёмная тема",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Скрыть фон",
|
||||
"lightTheme": "Светлая тема",
|
||||
"navbar": "Панель навигации",
|
||||
"novelInfo": "Информация о новелле",
|
||||
"pureBlackDarkMode": "Режим с чистым чёрным",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Показать историю в навигации",
|
||||
"showUpdatesInTheNav": "Показать историю в навигации",
|
||||
"themeMode": "Тема оформления",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Расширения",
|
||||
"deletePluginMessage": "Вы уверены, что хотите удалить %{name}?",
|
||||
"discover": "Узнайте больше",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Глобальный поиск",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Не удалось установить: %{name}",
|
||||
"installed": "Установлено",
|
||||
"installedPlugin": "Установлено %{name}",
|
||||
"installedPlugins": "Установленные плагины",
|
||||
"language": "Language",
|
||||
"lastUsed": "Последнее использование",
|
||||
"latest": "Последние",
|
||||
"listEmpty": "Включите языки в настройках",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Перенести %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Новелла уже в библиотеке",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Выберите источник",
|
||||
"selectSourceDesc": "Выберите источник для переноса из"
|
||||
"selectSourceDesc": "Выберите источник для переноса из",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "В вашей библиотеке нет новелл из этого источника",
|
||||
"pinnedPlugin": "Закреплён %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Закреплено",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Удалено из библиотеки",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Поиск источника",
|
||||
"searchResults": "Результаты поиска",
|
||||
"selectNovel": "Выбрать новеллу",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Удалено %{name}",
|
||||
"unpinnedPlugin": "Откреплено %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Ошибка обновления",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Обновлено до %{version}",
|
||||
"settings": {
|
||||
"title": "Настройки плагина",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "О программе",
|
||||
"add": "Добавить",
|
||||
"all": "Все",
|
||||
"back": "Back",
|
||||
"backup": "Резервная копия",
|
||||
"cancel": "Отменить",
|
||||
"categories": "Категории",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Фильтр",
|
||||
"globally": "глобально",
|
||||
"install": "Установить",
|
||||
"imported": "Imported",
|
||||
"logout": "Выйти",
|
||||
"name": "Название",
|
||||
"newUpdateAvailable": "Доступно новое обновление",
|
||||
"none": "None",
|
||||
"ok": "Ок",
|
||||
"close": "Close",
|
||||
"pause": "Пауза",
|
||||
"preparing": "Подготовка",
|
||||
"remove": "Удалить",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Продолжить",
|
||||
"retry": "Повторить",
|
||||
"save": "Сохранить",
|
||||
"saved": "Saved",
|
||||
"search": "Поиск",
|
||||
"searchFor": "Искать",
|
||||
"searchResults": "Результаты поиска",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Сортировка",
|
||||
"submit": "Продолжить",
|
||||
"loading": "Загрузка...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Внимание"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Обновить",
|
||||
"share": "Поделиться",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Открыть в браузере",
|
||||
"clearCookies": "Очистить cookies",
|
||||
"cookiesCleared": "Cookies очищены",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Либо глава пуста, либо приложению не удалось ее обработать",
|
||||
"chapterName": "Глава: %{name}",
|
||||
"completed": "Загрузка завершена",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Загрузка",
|
||||
"downloadingNovel": "Загружается %{name}",
|
||||
"downloadsLower": "Загруженное",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(По возрастанию)",
|
||||
"autoDownload": "Автозагрузка",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "По источникам",
|
||||
"chapterSort": "Сортировка глав по умолчанию",
|
||||
"desc": "(По убыванию)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "Может повысить производительность на медленных устройствах",
|
||||
"disableHapticFeedback": "Отключить виброотклик",
|
||||
"disableHapticFeedbackDescription": "Выключает вибрации для взаимодействия с касаниями.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Режим Отображения",
|
||||
"downloadNewChapters": "Скачивать новые главы",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "Расположение EPUB",
|
||||
"epubLocationDescription": "Место открытия и экспорта файлов EPUB.",
|
||||
"globalUpdate": "Обновить всё",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Размер сетки",
|
||||
"gridSizeDesc": "%{num} в ряд",
|
||||
"itemsPerRow": "элемента в ряду",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Сортировка тайтлов",
|
||||
"refreshMetadata": "Автоматически обновлять метаданные",
|
||||
"refreshMetadataDescription": "Проверять наличие новой обложки и описания при обновлении библиотеки",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Порядок сортировки",
|
||||
"updateLibrary": "Обновлять библиотеку при запуске",
|
||||
"updateLibraryDesc": "Не рекомендуется для слабых устройств",
|
||||
"updateTime": "Показать время последнего обновления",
|
||||
"useFAB": "Использовать FAB в библиотеке"
|
||||
"useFAB": "Использовать FAB в библиотеке",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "все источники",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Вы уверены? Вся история будет потеряна.",
|
||||
"deleted": "История удалена.",
|
||||
"nothingReadRecently": "Ничего не прочитано в последнее время",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Поиск в истории"
|
||||
},
|
||||
"library": "Библиотека",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Библиотека пуста. Добавьте новеллы из меню «Источники».",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Импорт EPUB",
|
||||
"openRandom": "Открыть случайную серию",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "В закладках",
|
||||
"downloaded": "Загружено",
|
||||
"unread": "Не прочитано"
|
||||
"unread": "Не прочитано",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "По названию главы",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Применить тему чтения к EPUB",
|
||||
"customJSWarning": "Пользовательский JS может поддерживаться не всеми программами чтения EPUB",
|
||||
"downloadedChaptersOnly": "Только загруженные главы будут включены в EPUB файл",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Экспорт всех глав",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Включить пользовательский CSS",
|
||||
"includeCustomJS": "Включить пользовательские JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Пожалуйста, введите правильный номер главы",
|
||||
"selectFolder": "Выберите папку для файла EPUB",
|
||||
"startChapter": "Начать главу",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Не удалось экспортировать EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Успешно экспортировано %{chapters} глав в EPUB",
|
||||
"noDownloadedChapters": "Загруженных глав не найдено. Пожалуйста, загрузите главы перед экспортом.",
|
||||
"noNovelSelected": "Ни одна новелла не выбрана для экспорта"
|
||||
"noNovelSelected": "Ни одна новелла не выбрана для экспорта",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Обложка сохранена",
|
||||
"coverNotSaved": "Обложка не сохранена",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Название главы",
|
||||
"chapterNumber": "Номер главы",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Введите допустимое название главы",
|
||||
"validChapterNumber": "Введите действительный номер главы"
|
||||
},
|
||||
"jumpToChapter": "Перейти к главе",
|
||||
"openChapter": "Открыть главу"
|
||||
"openChapter": "Открыть главу",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Перенос",
|
||||
"noSummary": "Нет сводки",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Выбор текста",
|
||||
"autoscroll": "Автопрокрутка",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Бионическое чтение",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Коснитесь для прокрутки",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Цвет",
|
||||
"display": "Display",
|
||||
"fontStyle": "Шрифт",
|
||||
"fullscreen": "Полноэкранный",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Высота строки",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Отступ",
|
||||
"pageReader": "Постраничное чтение (экспериментально)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Удалить лишние пробелы",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Смещение автопрокрутки (высота экрана по умолчанию)",
|
||||
"showBatteryAndTime": "Батарея и время",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Прогресс чтения",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Свайп между главами",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Выравнивание текста",
|
||||
"textSize": "Размер текста",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Вертикальная панель навигации",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Не выключать экран",
|
||||
"volumeButtonsScroll": "Прокрутка кноками громкости"
|
||||
"volumeButtonsScroll": "Прокрутка кноками громкости",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Прокрутить вниз",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Завершено",
|
||||
"nextChapter": "%{name}Следующий: %{name}",
|
||||
"noNextChapter": "Следующей главы нет",
|
||||
"noPreviousChapter": "Предыдущей главы нет"
|
||||
"noPreviousChapter": "Предыдущей главы нет",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Интервал прокрутки (секунды)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Цвет текста",
|
||||
"textColorModal": "Цвет текста",
|
||||
"title": "Чтение",
|
||||
"verticalSeekbarDesc": "Использовать вертикальную панель навигации"
|
||||
"verticalSeekbarDesc": "Использовать вертикальную панель навигации",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Ничего не найдено"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Статистика",
|
||||
"titlesInLibrary": "Названия в библиотеке",
|
||||
"totalChapters": "Всего глав",
|
||||
"unreadChapters": "Непрочитанные главы"
|
||||
"unreadChapters": "Непрочитанные главы",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Отслеживание",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Выйти из %{name}?",
|
||||
"revalidate": "Подтвердите еще раз",
|
||||
"services": "Сервисы отслеживания"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Импортирование EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Обновляем библиотеку",
|
||||
"DRIVE_BACKUP": "Резервное копирование на Google Диск",
|
||||
"DRIVE_RESTORE": "Восстановление Google Drive",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Локальное восстановление",
|
||||
"MIGRATE_NOVEL": "Миграция новелл",
|
||||
"DOWNLOAD_CHAPTER": "Загруженные главы"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Discover",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Global search",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "Last used",
|
||||
"latest": "Latest",
|
||||
"listEmpty": "Enable languages from settings",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Removed from library",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Search sources",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "Add",
|
||||
"all": "All",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "Cancel",
|
||||
"categories": "Categories",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filter",
|
||||
"globally": "globally",
|
||||
"install": "Install",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "Name",
|
||||
"newUpdateAvailable": "New update available",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"saved": "Saved",
|
||||
"search": "Search",
|
||||
"searchFor": "Search for",
|
||||
"searchResults": "Search results",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sort",
|
||||
"submit": "Submit",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "downloads",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "all sources",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Are you sure? All history will be lost.",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Search history"
|
||||
},
|
||||
"library": "Library",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Your library is empty. Add series to your library from Browse.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Chapter Name",
|
||||
"chapterNumber": "Chapter Number",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Enter a valid chapter name",
|
||||
"validChapterNumber": "Enter a valid chapter number"
|
||||
},
|
||||
"jumpToChapter": "Jump to Chapter",
|
||||
"openChapter": "Open Chapter"
|
||||
"openChapter": "Open Chapter",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Migrate",
|
||||
"noSummary": "No summary",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Color",
|
||||
"display": "Display",
|
||||
"fontStyle": "Font style",
|
||||
"fullscreen": "Fullscreen",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Text size",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Scroll to bottom",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Finished",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "There's no next chapter",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Text color",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Reader",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "No results found"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Statistics",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "Total chapters",
|
||||
"unreadChapters": "Unread chapters"
|
||||
"unreadChapters": "Unread chapters",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Veri Yönetimi",
|
||||
"deleteReadChapters": "Okunmuş bölümleri sil",
|
||||
"deleteReadChaptersDialogTitle": "Okunmuş olarak işaretlenmiş bütün bölümler silinecek.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "EPUB içeri aktar",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Romanları içeri aktar",
|
||||
"importStaticFiles": "İstatistik Dosyalarını İçeri Aktar",
|
||||
"novelInsertFailed": "roman yüklemesi başarısız",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Buton yerine FAB kullan",
|
||||
"userAgent": "Kullanıcı aracısı",
|
||||
"recreateDBIndexes": "Veritabanı indekskerini yenile",
|
||||
"recreateDBIndexesToast": "Veritabanı indeksleri yenilendi",
|
||||
"recreateDBIndexesDialogTitle": "Tüm veritabanı indeksleri yenilenecek. Bu biraz vakit alabilir.",
|
||||
"recreateDBIndexesDesc": "Veritabanı indekslerini yeniler. Yavaş cihazlarda hız artışı sağlayabilir."
|
||||
"recreateDBIndexesDesc": "Veritabanı indekslerini yeniler. Yavaş cihazlarda hız artışı sağlayabilir.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Görünüş",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "Uygulama teması",
|
||||
"darkTheme": "Karanlık Tema",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Arka planı gizle",
|
||||
"lightTheme": "Açık Tema",
|
||||
"navbar": "Menü Çubuğu",
|
||||
"novelInfo": "Roman hakkında",
|
||||
"pureBlackDarkMode": "Tamamen siyah karanlık tema",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Navigasyonda geçmişi göster",
|
||||
"showUpdatesInTheNav": "Menüde güncellemeleri göster",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Uzantılar",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Keşfet",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Genel arama",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Yükleme hatası: %{name}",
|
||||
"installed": "Yüklü",
|
||||
"installedPlugin": "%{name} yüklendi",
|
||||
"installedPlugins": "Yüklü uzantılar",
|
||||
"language": "Language",
|
||||
"lastUsed": "Son kullanılan",
|
||||
"latest": "En son",
|
||||
"listEmpty": "Ayarlardan dilleri etkinleştirin",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "%{url} birleştirilsin mi?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Roman kütüphanede mevcut",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Kaynak Seç",
|
||||
"selectSourceDesc": "Taşıyacağınız Kaynağı Seçin"
|
||||
"selectSourceDesc": "Taşıyacağınız Kaynağı Seçin",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Kütüphanenizde bu kaynaktan roman yok",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Kitaplıktan kaldırıldı",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Kaynak ara",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Roman Seç",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "%{name} kaldırıldı",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Güncelleme başarısız",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "%{version}' güncellendi",
|
||||
"settings": {
|
||||
"title": "Uzantı Ayarları",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "Hakkında",
|
||||
"add": "Ekle",
|
||||
"all": "Tümü",
|
||||
"back": "Back",
|
||||
"backup": "Yedek",
|
||||
"cancel": "İptal",
|
||||
"categories": "Kategoriler",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Filtre",
|
||||
"globally": "global olarak",
|
||||
"install": "Yükle",
|
||||
"imported": "Imported",
|
||||
"logout": "Çıkış yap",
|
||||
"name": "Ad",
|
||||
"newUpdateAvailable": "Yeni güncelleme var",
|
||||
"none": "None",
|
||||
"ok": "Tamam",
|
||||
"close": "Close",
|
||||
"pause": "Duraklat",
|
||||
"preparing": "Hazırlanıyor",
|
||||
"remove": "Kaldır",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Devam et",
|
||||
"retry": "Yeniden dene",
|
||||
"save": "Kaydet",
|
||||
"saved": "Saved",
|
||||
"search": "Ara",
|
||||
"searchFor": "Şunu ara",
|
||||
"searchResults": "Arama sonuçları",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sırala",
|
||||
"submit": "Gönder",
|
||||
"loading": "Yükleniyor ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Dikkat"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Yenile",
|
||||
"share": "Paylaş",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Tarayıcıda Aç",
|
||||
"clearCookies": "Çerezleri temizle",
|
||||
"cookiesCleared": "Çerezler temizlendi",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Bölüm boş veya uygulama veriyi alamadı",
|
||||
"chapterName": "Bölüm: %{name}",
|
||||
"completed": "İndirme tamamlandı",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "İndiriliyor",
|
||||
"downloadingNovel": "İndiriliyor: %{name}",
|
||||
"downloadsLower": "İndirilenler",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Artan)",
|
||||
"autoDownload": "Otomatik İndirme",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Kaynağa göre",
|
||||
"chapterSort": "Varsayılan bölüm sıralaması",
|
||||
"desc": "(Azalan)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "Yavaş cihazlarda performansı arttırabilir",
|
||||
"disableHapticFeedback": "Dokunmatik geri bildirimi devre dışı bırak",
|
||||
"disableHapticFeedbackDescription": "Dokunma geri bildirimleri için titreşimi devre dışı bırak.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Görünüm Modu",
|
||||
"downloadNewChapters": "Yeni bölümleri indir",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Konumu",
|
||||
"epubLocationDescription": "EPUB dosyalarınızı açıp, dışa aktardığınız yer.",
|
||||
"globalUpdate": "Global güncelleme",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Izgara boyutu",
|
||||
"gridSizeDesc": "Her bir satırda %{num}",
|
||||
"itemsPerRow": "Satır başına düşen öge",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sıralaması",
|
||||
"refreshMetadata": "Üst veriyi otomatik olarak yenile",
|
||||
"refreshMetadataDescription": "Kitaplığı güncellerken yeni kapak ve ayrıntıları denetle",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sıralama Düzeni",
|
||||
"updateLibrary": "Açılışta kitaplığı güncelle",
|
||||
"updateLibraryDesc": "Eski cihazlarda önerilmez",
|
||||
"updateTime": "Son güncelleme süresini göster",
|
||||
"useFAB": "Kitaplıkta FAB kullan"
|
||||
"useFAB": "Kitaplıkta FAB kullan",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "tüm kaynaklarda",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Emin misin? Tüm geçmiş kaybolacak.",
|
||||
"deleted": "Geçmiş silindi.",
|
||||
"nothingReadRecently": "Geçmiş yok",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Geçmişte ara"
|
||||
},
|
||||
"library": "Kitaplık",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Kitaplığın boş. Göz at yerinden kitaplığına light novel ekleyebilirsin.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "EPUB içe aktar",
|
||||
"openRandom": "Rastgele Girdi Aç",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "İşaretlenmiş",
|
||||
"downloaded": "İndirilmiş",
|
||||
"unread": "Okunmamış"
|
||||
"unread": "Okunmamış",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "Bölüm ismine göre",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Kapak kaydedildi",
|
||||
"coverNotSaved": "Kapak kaydedilemedi",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Bölüm Adı",
|
||||
"chapterNumber": "Bölüm Sayısı",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Geçerli bir bölüm adı girin",
|
||||
"validChapterNumber": "Geçerli bir bölüm sayısı girin"
|
||||
},
|
||||
"jumpToChapter": "Bölüme Atla",
|
||||
"openChapter": "Bölümü Aç"
|
||||
"openChapter": "Bölümü Aç",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Taşın",
|
||||
"noSummary": "Özet bilgisi yok",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Kaydırmak için tıkla",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Renk",
|
||||
"display": "Display",
|
||||
"fontStyle": "Yazı tipi",
|
||||
"fullscreen": "Tam ekran",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Kenar boşluğu",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Kaydırma miktarı (varsayılan olarak ekran yüksekliği)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Yazı boyutu",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Ekranı açık tut",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Alta kaydır",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Biten",
|
||||
"nextChapter": "Sonraki: %{name}",
|
||||
"noNextChapter": "Başka bölüm yok",
|
||||
"noPreviousChapter": "Önceki bölüm yok"
|
||||
"noPreviousChapter": "Önceki bölüm yok",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Yazı rengi",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Okuyucu",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Sonuç bulunamadı"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "İstatistikler",
|
||||
"titlesInLibrary": "Kitaplıktaki başlık",
|
||||
"totalChapters": "Toplam bölüm",
|
||||
"unreadChapters": "Okunmamış bölüm"
|
||||
"unreadChapters": "Okunmamış bölüm",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "İzleme",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "%{name}'tan çıkış yap?",
|
||||
"revalidate": "Yenşden doğrula",
|
||||
"services": "Servisler"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Керування даними",
|
||||
"deleteReadChapters": "Видалити прочитані розділи",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "імпортувати EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Імпортувати новелу",
|
||||
"importStaticFiles": "Імпортувати статичні файли",
|
||||
"novelInsertFailed": "не вдалося вставити новелу",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Використовувати FAB замість кнопки",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Зовнішній вигляд",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "Тема додатка",
|
||||
"darkTheme": "Темна тема",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Приховати фон",
|
||||
"lightTheme": "Світла тема",
|
||||
"navbar": "Панель навігації",
|
||||
"novelInfo": "Інформація про новелу",
|
||||
"pureBlackDarkMode": "Режим Pure Black",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Показувати історію в навігації",
|
||||
"showUpdatesInTheNav": "Показувати оновлення в навігації",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Доступно",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Огляд",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Глобальний пошук",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Помилка встановлення: %{name}",
|
||||
"installed": "Встановлено",
|
||||
"installedPlugin": "Встановлено плагін: %{name}",
|
||||
"installedPlugins": "Встановлені плагіни",
|
||||
"language": "Language",
|
||||
"lastUsed": "Останнє використане",
|
||||
"latest": "Останні",
|
||||
"listEmpty": "Увімкнути мови з налаштувань",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Перенести дані з %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Новела вже є в бібліотеці",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Виберіть джерело",
|
||||
"selectSourceDesc": "Виберіть джерело для перенесення"
|
||||
"selectSourceDesc": "Виберіть джерело для перенесення",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "У вашій бібліотеці немає новел з цього джерела",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Вилучено з бібліотеки",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Шукати джерела",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Виберіть новелу",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Видалено плагін: %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Помилка оновлення",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Оновлено до версії %{version}",
|
||||
"settings": {
|
||||
"title": "Налаштування плагінів",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "Про додаток",
|
||||
"add": "Додати",
|
||||
"all": "Всі",
|
||||
"back": "Back",
|
||||
"backup": "Резервна копія",
|
||||
"cancel": "Скасувати",
|
||||
"categories": "Категорії",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Фільтр",
|
||||
"globally": "глобально",
|
||||
"install": "Встановити",
|
||||
"imported": "Imported",
|
||||
"logout": "Вийти",
|
||||
"name": "Назва",
|
||||
"newUpdateAvailable": "Доступне нове оновлення",
|
||||
"none": "None",
|
||||
"ok": "Ок",
|
||||
"close": "Close",
|
||||
"pause": "Пауза",
|
||||
"preparing": "Підготовка",
|
||||
"remove": "Видалити",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Продовжити",
|
||||
"retry": "Повторити",
|
||||
"save": "Зберегти",
|
||||
"saved": "Saved",
|
||||
"search": "Пошук",
|
||||
"searchFor": "Шукати",
|
||||
"searchResults": "Результати пошуку",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Сортувати",
|
||||
"submit": "Надіслати",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Оновити",
|
||||
"share": "Поділитися",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Відкрити в браузері",
|
||||
"clearCookies": "Очистити куки",
|
||||
"cookiesCleared": "Куки очищено",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Розділ порожній або додаток не зміг його отримати",
|
||||
"chapterName": "Розділ: %{name}",
|
||||
"completed": "Завантаження завершено",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Завантаження",
|
||||
"downloadingNovel": "Завантаження: %{name}",
|
||||
"downloadsLower": "завантаження",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(За зростанням)",
|
||||
"autoDownload": "Автоматичне завантаження",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "За джерелом",
|
||||
"chapterSort": "Сортування розділів за замовчуванням",
|
||||
"desc": "(За спаданням)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "Може покращити продуктивність на повільних пристроях",
|
||||
"disableHapticFeedback": "Вимкнути тактильний зворотний зв'язок",
|
||||
"disableHapticFeedbackDescription": "Вимкнути вібрацію при дотиках.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Вигляд",
|
||||
"downloadNewChapters": "Завантажувати нові розділи",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "Розташування EPUB",
|
||||
"epubLocationDescription": "Місце, де ви відкриваєте та експортуєте свої EPUB-файли.",
|
||||
"globalUpdate": "Глобальне оновлення",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Розмір сітки",
|
||||
"gridSizeDesc": "%{num} в рядку",
|
||||
"itemsPerRow": "Елементів у рядку",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Сортування новел",
|
||||
"refreshMetadata": "Автоматично оновлювати метадані",
|
||||
"refreshMetadataDescription": "Перевіряти нові обкладинки та деталі при оновленні бібліотеки",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Порядок сортування",
|
||||
"updateLibrary": "Оновлювати бібліотеку при запуску",
|
||||
"updateLibraryDesc": "Не рекомендується для слабких пристроїв",
|
||||
"updateTime": "Показувати час останнього оновлення",
|
||||
"useFAB": "Використовувати FAB в бібліотеці"
|
||||
"useFAB": "Використовувати FAB в бібліотеці",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "всі джерела",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Ви впевнені? Вся історія буде втрачена.",
|
||||
"deleted": "Історію видалено.",
|
||||
"nothingReadRecently": "Нічого не читали останнім часом",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Шукати в історії"
|
||||
},
|
||||
"library": "Бібліотека",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Ваша бібліотека порожня. Додайте новели з Огляду.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Імпортувати EPUB",
|
||||
"openRandom": "Відкрити випадковий запис",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Закладки",
|
||||
"downloaded": "Завантажено",
|
||||
"unread": "Не прочитано"
|
||||
"unread": "Не прочитано",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "За назвою розділу",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Назва розділу",
|
||||
"chapterNumber": "Номер розділу",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Введіть дійсну назву розділу",
|
||||
"validChapterNumber": "Введіть дійсний номер розділу"
|
||||
},
|
||||
"jumpToChapter": "Перейти до Розділу",
|
||||
"openChapter": "Відкрити Розділ"
|
||||
"openChapter": "Відкрити Розділ",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Перенести",
|
||||
"noSummary": "Немає зведених відомостей",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Натисніть для прокрутки",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Колір",
|
||||
"display": "Display",
|
||||
"fontStyle": "Стиль шрифту",
|
||||
"fullscreen": "Повноекранний режим",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Відступи",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Обсяг прокручування (висота екрана за умовчанням)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Розмір тексту",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Не вимикати екран",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Прокрутити донизу",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Завершено",
|
||||
"nextChapter": "Наступний: %{name}",
|
||||
"noNextChapter": "Наступний розділ не знайдено",
|
||||
"noPreviousChapter": "Попереднього розділу немає"
|
||||
"noPreviousChapter": "Попереднього розділу немає",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Колір тексту",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Читалка",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Нічого не знайдено"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Статистика",
|
||||
"titlesInLibrary": "Назви у бібліотеці",
|
||||
"totalChapters": "Всього розділів",
|
||||
"unreadChapters": "Непрочитані розділи"
|
||||
"unreadChapters": "Непрочитані розділи",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Відстеження",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Вийти з %{name}?",
|
||||
"revalidate": "Перевірити знову",
|
||||
"services": "Сервіси"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Quản lý dữ liệu",
|
||||
"deleteReadChapters": "Xóa chương đã đọc",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Nhập file EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Nhập truyện",
|
||||
"importStaticFiles": "Nhập tệp tin tĩnh",
|
||||
"novelInsertFailed": "lỗi khi thêm truyện",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Sử dụng nút nổi",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Giao diện",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "Chủ đề",
|
||||
"darkTheme": "Màu tối",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Ẩn bóng",
|
||||
"lightTheme": "Màu sáng",
|
||||
"navbar": "Thanh điều hướng",
|
||||
"novelInfo": "Thông tin truyện",
|
||||
"pureBlackDarkMode": "Màu đen tuyền",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Hiển thị mục lịch sử",
|
||||
"showUpdatesInTheNav": "Hiển thị mục cập nhật",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Sẵn có",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "Khám phá",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "Tìm kiếm mở rộng",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Cài đặt lỗi: %{name}",
|
||||
"installed": "Đã cài đặt",
|
||||
"installedPlugin": "Đã cài đặt %{name}",
|
||||
"installedPlugins": "Nguồn đã cài đặt",
|
||||
"language": "Language",
|
||||
"lastUsed": "Lần sử dụng trước",
|
||||
"latest": "Mới nhất",
|
||||
"listEmpty": "Chọn ngôn ngữ",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Chuyển đổi sang %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Truyện đã có trong thư viện",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Chọn nguồn",
|
||||
"selectSourceDesc": "Chọn nguồn cần chuyển đổi"
|
||||
"selectSourceDesc": "Chọn nguồn cần chuyển đổi",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Thư viện của bạn không có truyện nào từ nguồn này",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "Đã xoá khỏi thư viện",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "Tìm nguồn truyện",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Chọn truyện",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Gỡ cài đặt %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Cập nhật thất bại",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Đã cập nhật lên %{version}",
|
||||
"settings": {
|
||||
"title": "Cài đặt nguồn",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "Thông tin",
|
||||
"add": "Thêm",
|
||||
"all": "Tất cả",
|
||||
"back": "Back",
|
||||
"backup": "Sao lưu",
|
||||
"cancel": "Hủy",
|
||||
"categories": "Danh mục",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "Bộ lọc",
|
||||
"globally": "toàn cầu",
|
||||
"install": "Tải về",
|
||||
"imported": "Imported",
|
||||
"logout": "Đăng xuất",
|
||||
"name": "Tên",
|
||||
"newUpdateAvailable": "Đã có bản cập nhật mới",
|
||||
"none": "None",
|
||||
"ok": "Ok",
|
||||
"close": "Close",
|
||||
"pause": "Tạm dừng",
|
||||
"preparing": "Đang chuẩn bị",
|
||||
"remove": "Xoá",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Tiếp tục",
|
||||
"retry": "Thử lại",
|
||||
"save": "Lưu",
|
||||
"saved": "Saved",
|
||||
"search": "Tìm kiếm",
|
||||
"searchFor": "Tìm kiếm",
|
||||
"searchResults": "Kết quả tìm kiếm",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "Sắp xếp",
|
||||
"submit": "Gửi",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Làm mới",
|
||||
"share": "Chia sẻ",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Mở trong trình duyệt",
|
||||
"clearCookies": "Xoá cookie",
|
||||
"cookiesCleared": "Cookie đã được xoá",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Chương truyện trống hoặc ứng dụng không thể cào nó",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Tải xuống hoàn thành",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Đang tải xuống",
|
||||
"downloadingNovel": "Đang tải: %{name}",
|
||||
"downloadsLower": "tải xuống",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Tăng dần)",
|
||||
"autoDownload": "Tự động tải xuống",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "Theo nguồn",
|
||||
"chapterSort": "Sắp xếp mặc định",
|
||||
"desc": "(Giảm dần)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "Có thể cải thiện hiệu năng ở máy yếu",
|
||||
"disableHapticFeedback": "Tắt phản hồi xúc giác",
|
||||
"disableHapticFeedbackDescription": "Tắt rung khi chạm.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Chế độ Hiển thị",
|
||||
"downloadNewChapters": "Tải chương mới",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Cập nhật toàn bộ",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Dạng lưới",
|
||||
"gridSizeDesc": "%{num} truyện mỗi hàng",
|
||||
"itemsPerRow": "Truyện trên hàng",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Sắp xếp truyện",
|
||||
"refreshMetadata": "Tự động làm mới metadata",
|
||||
"refreshMetadataDescription": "Kiểm tra ảnh bìa và mô tả khi cập nhật thự viện",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Thứ tự sắp xếp",
|
||||
"updateLibrary": "Cập nhật thư viện khi khởi động",
|
||||
"updateLibraryDesc": "Không khuyến khích cho thiết bị yếu",
|
||||
"updateTime": "Hiện lần cập nhật trước",
|
||||
"useFAB": "Sử dụng FAB trong thư viện"
|
||||
"useFAB": "Sử dụng FAB trong thư viện",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "toàn bộ nguồn",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "Bạn có chắc không? Toàn bộ lịch sử sẽ bị xoá.",
|
||||
"deleted": "Lịch sử đã được xoá.",
|
||||
"nothingReadRecently": "Không đọc gì gần đây",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "Tìm trong lịch sử"
|
||||
},
|
||||
"library": "Thư viện",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "Không có gì cả. Hãy thêm truyện vào thư viện từ mục Tìm kiếm.",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Nhập file EPUB",
|
||||
"openRandom": "Mở truyện ngẫu nhiên",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Đã đánh dấu",
|
||||
"downloaded": "Đã tải xuống",
|
||||
"unread": "Chưa đọc"
|
||||
"unread": "Chưa đọc",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "Theo tên chương",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "Tên Chương",
|
||||
"chapterNumber": "Chương Số",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "Vui lòng nhập tên chương hợp lệ",
|
||||
"validChapterNumber": "Vui lòng nhập số chương hợp lệ"
|
||||
},
|
||||
"jumpToChapter": "Đi tới Chương",
|
||||
"openChapter": "Đọc luôn"
|
||||
"openChapter": "Đọc luôn",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "Đồng bộ",
|
||||
"noSummary": "Không có tóm tắt",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Ấn để cuộn",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "Màu chữ",
|
||||
"display": "Display",
|
||||
"fontStyle": "Phông chữ",
|
||||
"fullscreen": "Toàn màn hình",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Khoảng đệm",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "Cỡ chữ",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Giữ màn hình luôn sáng",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "Xuống cuối",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "Đã xong",
|
||||
"nextChapter": "Tiếp: %{name}",
|
||||
"noNextChapter": "Không có chương kế tiếp",
|
||||
"noPreviousChapter": "Không có chương kế tiếp"
|
||||
"noPreviousChapter": "Không có chương kế tiếp",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "Màu chữ",
|
||||
"textColorModal": "Text color",
|
||||
"title": "Trang đọc",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "Không tìm thấy kết quả"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "Thống kê",
|
||||
"titlesInLibrary": "Tiêu đề",
|
||||
"totalChapters": "Chương",
|
||||
"unreadChapters": "Chương chưa đọc"
|
||||
"unreadChapters": "Chương chưa đọc",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Theo dõi",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Đăng xuất khỏi %{name}?",
|
||||
"revalidate": "Xác thực lại",
|
||||
"services": "Dịch vụ"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "数据",
|
||||
"deleteReadChapters": "删除已读章节",
|
||||
"deleteReadChaptersDialogTitle": "所有标记为已读的章节将被删除。",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "导入 EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "导入小说",
|
||||
"importStaticFiles": "导入静态文件",
|
||||
"novelInsertFailed": "小说插入失败",
|
||||
"networking": "Networking",
|
||||
"useFAB": "使用浮动操作按钮",
|
||||
"userAgent": "用户代理",
|
||||
"recreateDBIndexes": "重建数据库索引",
|
||||
"recreateDBIndexesToast": "数据库索引已重建",
|
||||
"recreateDBIndexesDialogTitle": "所有数据库索引将被重建。\n此操作可能需要一些时间。",
|
||||
"recreateDBIndexesDesc": "重建数据库索引,可提升低性能设备运行效率。"
|
||||
"recreateDBIndexesDesc": "重建数据库索引,可提升低性能设备运行效率。",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "外观",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "默认",
|
||||
"appTheme": "主题",
|
||||
"darkTheme": "深色",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "隐藏背景",
|
||||
"lightTheme": "浅色",
|
||||
"navbar": "导航栏",
|
||||
"novelInfo": "小说信息",
|
||||
"pureBlackDarkMode": "纯黑深色模式",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "在导航中显示历史",
|
||||
"showUpdatesInTheNav": "在导航中显示更新",
|
||||
"themeMode": "主题模式",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "可用",
|
||||
"deletePluginMessage": "您确定要卸载 %{name} 吗?",
|
||||
"discover": "发现",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "全局搜索",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "安装失败:%{name}",
|
||||
"installed": "已安装",
|
||||
"installedPlugin": "已安装 %{name}",
|
||||
"installedPlugins": "已安装插件",
|
||||
"language": "Language",
|
||||
"lastUsed": "最近使用",
|
||||
"latest": "最新",
|
||||
"listEmpty": "从设置中启用语言",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "迁移 %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "小说已经在书库中",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "选择源",
|
||||
"selectSourceDesc": "选择要迁移的源"
|
||||
"selectSourceDesc": "选择要迁移的源",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "您的图书馆没有该源的任何小说",
|
||||
"pinnedPlugin": "已置顶%{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "已置顶的插件",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "已从书库中删除",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "搜索资源",
|
||||
"searchResults": "搜索结果",
|
||||
"selectNovel": "选择小说",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "已卸载 %{name}",
|
||||
"unpinnedPlugin": "已取消置顶%{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "更新失败",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "已更新至 %{version}",
|
||||
"settings": {
|
||||
"title": "插件设置",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "关于",
|
||||
"add": "添加",
|
||||
"all": "全部",
|
||||
"back": "Back",
|
||||
"backup": "备份",
|
||||
"cancel": "取消",
|
||||
"categories": "分类",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "筛选",
|
||||
"globally": "全局",
|
||||
"install": "安装",
|
||||
"imported": "Imported",
|
||||
"logout": "登出",
|
||||
"name": "名称",
|
||||
"newUpdateAvailable": "新版本可用",
|
||||
"none": "None",
|
||||
"ok": "确定",
|
||||
"close": "Close",
|
||||
"pause": "暂停",
|
||||
"preparing": "准备中",
|
||||
"remove": "移除",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "继续",
|
||||
"retry": "重试",
|
||||
"save": "保存",
|
||||
"saved": "Saved",
|
||||
"search": "搜索",
|
||||
"searchFor": "搜索",
|
||||
"searchResults": "搜索结果",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "排序",
|
||||
"submit": "确定",
|
||||
"loading": "正在加载...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "警告"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "刷新",
|
||||
"share": "分享",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "在浏览器中打开",
|
||||
"clearCookies": "清除Cookie",
|
||||
"cookiesCleared": "Cookie已清除",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "章节为空或应用无法抓取",
|
||||
"chapterName": "章节:%{name}",
|
||||
"completed": "下载完成",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "正在下载",
|
||||
"downloadingNovel": "正在下载:%{name}",
|
||||
"downloadsLower": "下载",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(递增)",
|
||||
"autoDownload": "自动下载",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "按源",
|
||||
"chapterSort": "默认章节排序",
|
||||
"desc": "(递减)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "可能会在运行缓慢的设备上提高性能",
|
||||
"disableHapticFeedback": "禁用振动反馈",
|
||||
"disableHapticFeedbackDescription": "关闭交互时产生的振动。",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "显示模式",
|
||||
"downloadNewChapters": "下载新章节",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB 位置",
|
||||
"epubLocationDescription": "打开或导入您的 EPUB 文件的位置。",
|
||||
"globalUpdate": "全局更新",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "网格尺寸",
|
||||
"gridSizeDesc": "每行 %{num} 列",
|
||||
"itemsPerRow": "每行的项目数",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "小说排序",
|
||||
"refreshMetadata": "自动更新元数据",
|
||||
"refreshMetadataDescription": "更新书库时同时更新封面和详情",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "排序",
|
||||
"updateLibrary": "打开应用时更新书库",
|
||||
"updateLibraryDesc": "不推荐在低端设备上启用",
|
||||
"updateTime": "显示上次更新时间",
|
||||
"useFAB": "在书库中使用浮动操作按钮"
|
||||
"useFAB": "在书库中使用浮动操作按钮",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "所有源",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "您确定吗?所有历史记录都将删除。",
|
||||
"deleted": "历史记录已删除。",
|
||||
"nothingReadRecently": "最近没读过什么",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "搜索历史记录"
|
||||
},
|
||||
"library": "书库",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "您的书库是空的。请从浏览将小说添加到您的书库中。",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "导入EPUB",
|
||||
"openRandom": "随机打开",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "已添加书签",
|
||||
"downloaded": "已下载",
|
||||
"unread": "未读"
|
||||
"unread": "未读",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "按章节名",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "将阅读器主题应用到EPUB",
|
||||
"customJSWarning": "不是所有EPUB阅读器都能够支持自定义JS",
|
||||
"downloadedChaptersOnly": "EPUB文件中只包含已下载的章节",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "结束章节",
|
||||
"export": "Export",
|
||||
"exportAll": "导出所有章节",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "包含自定义CSS",
|
||||
"includeCustomJS": "包括自定义JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "请输入有效的章节数字",
|
||||
"selectFolder": "选择EPUB文件的目标文件夹",
|
||||
"startChapter": "起始章节",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "导出EPUB失败:%{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "成功将%{chapters}个章节导出为EPUB",
|
||||
"noDownloadedChapters": "未找到已下载的章节,请在导出前下载章节。",
|
||||
"noNovelSelected": "没有小说被选中导出"
|
||||
"noNovelSelected": "没有小说被选中导出",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "封面已保存",
|
||||
"coverNotSaved": "封面未保存",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "章节名",
|
||||
"chapterNumber": "章节编号",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "输入有效的章节名",
|
||||
"validChapterNumber": "输入有效的章节编号"
|
||||
},
|
||||
"jumpToChapter": "跳转到章节",
|
||||
"openChapter": "打开章节"
|
||||
"openChapter": "打开章节",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "迁移",
|
||||
"noSummary": "无简介",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "文本选择",
|
||||
"autoscroll": "自动滚屏",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "仿真阅读",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "点击滚屏",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "颜色",
|
||||
"display": "Display",
|
||||
"fontStyle": "字体样式",
|
||||
"fullscreen": "全屏",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "行高",
|
||||
"navigation": "Navigation",
|
||||
"padding": "内边距",
|
||||
"pageReader": "分页阅读(实验性)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "删除额外间距",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "滚动长度 (默认屏幕高度)",
|
||||
"showBatteryAndTime": "电池和时间",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "阅读进度",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "在章节之间滑动",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "文本对齐",
|
||||
"textSize": "文本大小",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "滑动打开抽屉栏",
|
||||
"verticalSeekbar": "垂直进度条",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "保持屏幕开启",
|
||||
"volumeButtonsScroll": "音量按键滚屏"
|
||||
"volumeButtonsScroll": "音量按键滚屏",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "滚动到底部",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "已完成",
|
||||
"nextChapter": "下一章: %{name}",
|
||||
"noNextChapter": "没有下一章节",
|
||||
"noPreviousChapter": "没有上一章节"
|
||||
"noPreviousChapter": "没有上一章节",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "滚屏间隔 (秒)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "文字颜色",
|
||||
"textColorModal": "文字颜色",
|
||||
"title": "阅读器",
|
||||
"verticalSeekbarDesc": "使用垂直进度条"
|
||||
"verticalSeekbarDesc": "使用垂直进度条",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "未找到相应结果"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "统计数据",
|
||||
"titlesInLibrary": "书库中的小说",
|
||||
"totalChapters": "统计数据",
|
||||
"unreadChapters": "未读章节"
|
||||
"unreadChapters": "未读章节",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "进度记录",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "从 %{name} 注销?",
|
||||
"revalidate": "重新认证",
|
||||
"services": "服务"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "导入EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "正在更新书库",
|
||||
"DRIVE_BACKUP": "Google云端硬盘备份",
|
||||
"DRIVE_RESTORE": "Google云端硬盘恢复",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "本地恢复",
|
||||
"MIGRATE_NOVEL": "正在迁移小说",
|
||||
"DOWNLOAD_CHAPTER": "正在下载章节"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@
|
||||
"dataManagement": "Data Management",
|
||||
"deleteReadChapters": "Delete read chapters",
|
||||
"deleteReadChaptersDialogTitle": "All chapters marked as read will be deleted.",
|
||||
"disabled": "Disabled",
|
||||
"dnsOverHttps": "DNS over HTTPS (DoH)",
|
||||
"dnsOverHttpsDescription": "Uses the selected resolver for app requests and downloads. WebView traffic is not affected.",
|
||||
"importEpub": "Import EPUB",
|
||||
"importFailed": "Error importing EPUB:",
|
||||
"importNovel": "Import Novel",
|
||||
"importStaticFiles": "Import Static Files",
|
||||
"novelInsertFailed": "novel insert failed",
|
||||
"networking": "Networking",
|
||||
"useFAB": "Use FAB instead of button",
|
||||
"userAgent": "User Agent",
|
||||
"recreateDBIndexes": "Recreate DB indexes",
|
||||
"recreateDBIndexesToast": "Recreated DB indexes",
|
||||
"recreateDBIndexesDialogTitle": "All DB indexes will be recreated.\nThis may take a while.",
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices."
|
||||
"recreateDBIndexesDesc": "Recreates DB indexes. This may improve performance on slower devices.",
|
||||
"restartRequired": "Restart LNReader to apply this change."
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"appearanceScreen": {
|
||||
@@ -45,11 +51,16 @@
|
||||
"appLanguageDefault": "Default",
|
||||
"appTheme": "App theme",
|
||||
"darkTheme": "Dark Theme",
|
||||
"dateFormat": "Date format",
|
||||
"dateFormatDefault": "Default (%{date})",
|
||||
"dynamicColors": "Dynamic",
|
||||
"hideBackdrop": "Hide backdrop",
|
||||
"lightTheme": "Light Theme",
|
||||
"navbar": "Navbar",
|
||||
"novelInfo": "Novel info",
|
||||
"pureBlackDarkMode": "Pure black dark mode",
|
||||
"relativeTimestamps": "Relative timestamps",
|
||||
"relativeTimestampsDescription": "\"Today\" instead of \"%{date}\"",
|
||||
"showHistoryInTheNav": "Show history in the nav",
|
||||
"showUpdatesInTheNav": "Show updates in the nav",
|
||||
"themeMode": "Theme mode",
|
||||
@@ -136,30 +147,58 @@
|
||||
"available": "Available",
|
||||
"deletePluginMessage": "Are you sure you want to uninstall %{name}?",
|
||||
"discover": "发现",
|
||||
"editPluginSetting": "Edit %{name}",
|
||||
"globalSearch": "全局搜索",
|
||||
"installPlugin": "Install %{name}",
|
||||
"installFailed": "Installation failed: %{name}",
|
||||
"installed": "Installed",
|
||||
"installedPlugin": "Installed %{name}",
|
||||
"installedPlugins": "Installed plugins",
|
||||
"language": "Language",
|
||||
"lastUsed": "最近使用",
|
||||
"latest": "最新",
|
||||
"listEmpty": "从设置中启用语言",
|
||||
"migration": {
|
||||
"cover": "Cover",
|
||||
"dialogMessage": "Migrate %{url}?",
|
||||
"keepCurrent": "Keep current",
|
||||
"metadata": "Novel details",
|
||||
"novelAlreadyInLibrary": "Novel already in library",
|
||||
"preservedState": "Categories, matched chapter progress and bookmarks, and reader settings will be preserved.",
|
||||
"redownloadChapters": "Re-download matching downloaded chapters",
|
||||
"reviewDescription": "Choose what to keep when migrating to %{name}.",
|
||||
"reviewTitle": "Review migration",
|
||||
"selectSource": "Select Source",
|
||||
"selectSourceDesc": "Select a Source To Migrate From"
|
||||
"selectSourceDesc": "Select a Source To Migrate From",
|
||||
"useDestination": "Use destination source"
|
||||
},
|
||||
"noSource": "Your library does not have any novels from this source",
|
||||
"pinnedPlugin": "Pinned %{name}",
|
||||
"noPlugins": "No plugins found. Add a repository or enable more languages in Browse Settings.",
|
||||
"noSearchResults": "No matching results",
|
||||
"noSources": "No sources installed. Install a plugin to start browsing novels.",
|
||||
"openPluginDetails": "Open details for %{name}",
|
||||
"openPluginSettings": "Open settings for %{name}",
|
||||
"openWebsite": "Open the website for %{name}",
|
||||
"pinSource": "Pin %{name}",
|
||||
"pinnedPlugins": "Pinned plugins",
|
||||
"pluginDetails": "Plugin details",
|
||||
"pluginIcon": "plugin icon",
|
||||
"pluginNotInstalled": "This plugin is not installed",
|
||||
"plugins": "Plugins",
|
||||
"removeFromLibrary": "從書庫中移除",
|
||||
"repositories": "Repositories",
|
||||
"searchbar": "搜索资源",
|
||||
"searchResults": "Search results",
|
||||
"selectNovel": "Select Novel",
|
||||
"sources": "Sources",
|
||||
"togglePluginSetting": "Toggle %{name}",
|
||||
"uninstalledPlugin": "Uninstalled %{name}",
|
||||
"unpinnedPlugin": "Unpinned %{name}",
|
||||
"uninstall": "Uninstall",
|
||||
"unpinSource": "Unpin %{name}",
|
||||
"updatePlugin": "Update %{name}",
|
||||
"updateAll": "Update all",
|
||||
"updateFailed": "Update failed",
|
||||
"updatesPending": "Updates pending",
|
||||
"updatedTo": "Updated to %{version}",
|
||||
"settings": {
|
||||
"title": "Plugin Settings",
|
||||
@@ -196,6 +235,7 @@
|
||||
"about": "About",
|
||||
"add": "新增",
|
||||
"all": "全部",
|
||||
"back": "Back",
|
||||
"backup": "Backup",
|
||||
"cancel": "取消",
|
||||
"categories": "類別",
|
||||
@@ -213,10 +253,13 @@
|
||||
"filter": "筛选",
|
||||
"globally": "全球",
|
||||
"install": "安裝",
|
||||
"imported": "Imported",
|
||||
"logout": "Logout",
|
||||
"name": "名稱",
|
||||
"newUpdateAvailable": "有可用更新",
|
||||
"none": "None",
|
||||
"ok": "确定",
|
||||
"close": "Close",
|
||||
"pause": "Pause",
|
||||
"preparing": "Preparing",
|
||||
"remove": "Remove",
|
||||
@@ -225,6 +268,7 @@
|
||||
"resume": "Resume",
|
||||
"retry": "重試",
|
||||
"save": "保存",
|
||||
"saved": "Saved",
|
||||
"search": "搜索",
|
||||
"searchFor": "搜尋",
|
||||
"searchResults": "搜尋結果",
|
||||
@@ -235,11 +279,13 @@
|
||||
"sort": "排序",
|
||||
"submit": "提交",
|
||||
"loading": "Loading ...",
|
||||
"moreOptions": "More options",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"webview": {
|
||||
"refresh": "Refresh",
|
||||
"share": "Share",
|
||||
"openInWebView": "Open in WebView",
|
||||
"openInBrowser": "Open in browser",
|
||||
"clearCookies": "Clear cookies",
|
||||
"cookiesCleared": "Cookies cleared",
|
||||
@@ -260,6 +306,7 @@
|
||||
"chapterEmptyOrScrapeError": "Either chapter is empty or the app couldn't scrape it",
|
||||
"chapterName": "Chapter: %{name}",
|
||||
"completed": "Download completed",
|
||||
"storageInfo": "Downloaded chapters are stored in the app's private storage on this device.",
|
||||
"downloading": "Downloading",
|
||||
"downloadingNovel": "Downloading: %{name}",
|
||||
"downloadsLower": "下載",
|
||||
@@ -271,6 +318,14 @@
|
||||
"generalSettingsScreen": {
|
||||
"asc": "(Ascending)",
|
||||
"autoDownload": "Auto-download",
|
||||
"automaticUpdates": "Automatic updates",
|
||||
"automaticUpdatesDaily": "Daily",
|
||||
"automaticUpdatesDescription": "Runs when a network connection is available. Android may delay background work to save battery.",
|
||||
"automaticUpdatesEvery12Hours": "Every 12 hours",
|
||||
"automaticUpdatesEvery2Days": "Every 2 days",
|
||||
"automaticUpdatesEvery3Days": "Every 3 days",
|
||||
"automaticUpdatesOff": "Off",
|
||||
"automaticUpdatesWeekly": "Weekly",
|
||||
"bySource": "By source",
|
||||
"chapterSort": "Default chapter sort",
|
||||
"desc": "(Descending)",
|
||||
@@ -278,12 +333,20 @@
|
||||
"disableLoadingAnimationsDesc": "May improve performance on slower devices",
|
||||
"disableHapticFeedback": "Disable haptic feedback",
|
||||
"disableHapticFeedbackDescription": "Turn off vibrations for touch interactions.",
|
||||
"chapterDownloadCooldown": "Chapter download cooldown",
|
||||
"chapterDownloadCooldownDesc": "Wait between sequential chapter downloads (seconds). Helps avoid source rate limits during batch downloads.",
|
||||
"chapterDownloadCooldownPlaceholder": "Cooldown in seconds (e.g. 1.5)",
|
||||
"chapterDownloadCooldownWarning": "Very low cooldowns may trigger rate limiting or temporary IP bans from sources.",
|
||||
"displayMode": "Display Mode",
|
||||
"downloadNewChapters": "Download new chapters",
|
||||
"epub": "EPUB",
|
||||
"epubLocation": "EPUB Location",
|
||||
"epubLocationDescription": "The place where you open and export your EPUB files.",
|
||||
"globalUpdate": "Global update",
|
||||
"globalUpdateCategories": "Categories",
|
||||
"globalUpdateCategoriesDescription": "Novels in excluded categories will not be updated, even when they are also in an included category. Tap a category to cycle between included, excluded, and neither.",
|
||||
"globalUpdateExclude": "Exclude: %{categories}",
|
||||
"globalUpdateInclude": "Include: %{categories}",
|
||||
"gridSize": "Grid size",
|
||||
"gridSizeDesc": "%{num} per row",
|
||||
"itemsPerRow": "Items per row",
|
||||
@@ -294,11 +357,21 @@
|
||||
"novelSort": "Novel Sort",
|
||||
"refreshMetadata": "Automatically refresh metadata",
|
||||
"refreshMetadataDescription": "Check for new cover and details when updating library",
|
||||
"smartUpdate": "Smart update",
|
||||
"smartUpdateSkipCompleted": "Skip entries with \"Completed\" status",
|
||||
"smartUpdateSkipUnstarted": "Skip unstarted entries",
|
||||
"smartUpdateSkipWithUnread": "Skip entries with unread chapter(s)",
|
||||
"sortOrder": "Sort Order",
|
||||
"updateLibrary": "Update library on launch",
|
||||
"updateLibraryDesc": "Not recommended for low devices",
|
||||
"updateTime": "Show last update time",
|
||||
"useFAB": "Use FAB in Library"
|
||||
"useFAB": "Use FAB in Library",
|
||||
"timeTracking": "Time Tracking",
|
||||
"enableTimeTracking": "Enable time tracking",
|
||||
"enableTimeTrackingDesc": "Tracks time spent reading and displays it in the statistics screen",
|
||||
"inactivityTimeout": "Inactivity Timeout",
|
||||
"inactivityTimeoutNever": "Never",
|
||||
"inactivityTimeoutDesc": "Automatically pause time tracking after a period of inactivity"
|
||||
},
|
||||
"globalSearch": {
|
||||
"allSources": "所有源",
|
||||
@@ -310,6 +383,8 @@
|
||||
"clearHistorWarning": "您确定吗?所有历史记录都将删除。",
|
||||
"deleted": "History deleted.",
|
||||
"nothingReadRecently": "Nothing read recently",
|
||||
"removeHistoryWarning": "This will remove the read date of this chapter. Are you sure?",
|
||||
"resetAllChapters": "Reset all chapters for this entry",
|
||||
"searchbar": "搜索历史记录"
|
||||
},
|
||||
"library": "书库",
|
||||
@@ -346,6 +421,7 @@
|
||||
}
|
||||
},
|
||||
"empty": "您的库是空的。从浏览添加丛书到您的库里。",
|
||||
"emptyCategory": "This category is empty.",
|
||||
"extraMenu": {
|
||||
"importEpub": "Import EPUB",
|
||||
"openRandom": "Open Random Entry",
|
||||
@@ -372,7 +448,8 @@
|
||||
"filters": {
|
||||
"bookmarked": "Bookmarked",
|
||||
"downloaded": "Downloaded",
|
||||
"unread": "Unread"
|
||||
"unread": "Unread",
|
||||
"scanlators": "Ignore scanlators"
|
||||
},
|
||||
"order": {
|
||||
"byChapterName": "By chapter name",
|
||||
@@ -385,11 +462,16 @@
|
||||
"exportEpubModal": {
|
||||
"applyReaderTheme": "Apply reader theme to EPUB",
|
||||
"customJSWarning": "Custom JS may not be supported by all EPUB readers",
|
||||
"downloadedChaptersOnly": "Only downloaded chapters will be included in the EPUB file",
|
||||
"description": "Choose a destination and which downloaded chapters to include in the EPUB.",
|
||||
"directory": "Directory",
|
||||
"endChapter": "End Chapter",
|
||||
"export": "Export",
|
||||
"exportAll": "Export All Chapters",
|
||||
"fileName": "File name",
|
||||
"fileNameRequired": "Enter a file name",
|
||||
"includeCustomCSS": "Include Custom CSS",
|
||||
"includeCustomJS": "Include Custom JS",
|
||||
"includeChapterNumber": "Include chapter number in chapter titles",
|
||||
"invalidRange": "Please enter valid chapter numbers",
|
||||
"selectFolder": "Select destination folder for EPUB file",
|
||||
"startChapter": "Start Chapter",
|
||||
@@ -398,9 +480,12 @@
|
||||
},
|
||||
"epub": {
|
||||
"exportFailed": "Failed to export EPUB: %{error}",
|
||||
"exportingChapter": "%{current}/%{total} · %{chapter}",
|
||||
"exportSuccess": "Successfully exported %{chapters} chapters as EPUB",
|
||||
"noDownloadedChapters": "No downloaded chapters found. Please download chapters before exporting.",
|
||||
"noNovelSelected": "No novel selected for export"
|
||||
"noNovelSelected": "No novel selected for export",
|
||||
"preparingExport": "Preparing EPUB",
|
||||
"savingExport": "Saving EPUB"
|
||||
},
|
||||
"coverSaved": "Cover saved",
|
||||
"coverNotSaved": "Cover not saved",
|
||||
@@ -429,12 +514,16 @@
|
||||
"jumpToChapterModal": {
|
||||
"chapterName": "章節名稱",
|
||||
"chapterNumber": "章節編號",
|
||||
"description": "Search by chapter number or name, then choose whether to open it or scroll to it in the chapter list.",
|
||||
"error": {
|
||||
"validChapterName": "請輸入有效的章節名稱",
|
||||
"validChapterNumber": "請輸入有效的章節編號"
|
||||
},
|
||||
"jumpToChapter": "跳轉至章節",
|
||||
"openChapter": "打開章節"
|
||||
"openChapter": "打開章節",
|
||||
"openChapterDescription": "Turn off to scroll to it in the chapter list.",
|
||||
"searchByName": "Search by Chapter Name",
|
||||
"searchByNameDescription": "Turn off to search by chapter number."
|
||||
},
|
||||
"migrate": "迁移",
|
||||
"noSummary": "無總結",
|
||||
@@ -458,27 +547,47 @@
|
||||
},
|
||||
"readerScreen": {
|
||||
"bottomSheet": {
|
||||
"alignCenter": "Center",
|
||||
"alignJustify": "Justify",
|
||||
"alignLeft": "Left",
|
||||
"alignRight": "Right",
|
||||
"allowTextSelection": "Text selection",
|
||||
"autoscroll": "Auto-scroll",
|
||||
"autoscrollDescription": "Scroll the page automatically at a steady pace",
|
||||
"bionicReading": "Bionic reading",
|
||||
"bionicReadingDescription": "Bold the start of each word to help your eyes track faster",
|
||||
"tapToScroll": "Tap to scroll",
|
||||
"tapToScrollDescription": "Tap the top or bottom of the screen to scroll through the chapter",
|
||||
"color": "颜色",
|
||||
"display": "Display",
|
||||
"fontStyle": "字体样式",
|
||||
"fullscreen": "全屏",
|
||||
"fullscreenDescription": "Hide the status bar and navigation bar while reading",
|
||||
"lineHeight": "Line height",
|
||||
"navigation": "Navigation",
|
||||
"padding": "Padding",
|
||||
"pageReader": "Paged reading (Experimental)",
|
||||
"pageReaderDescription": "Split the chapter into pages instead of scrolling. Experimental — may break formatting in some novels",
|
||||
"removeExtraSpacing": "Remove extra spacing",
|
||||
"removeExtraSpacingDescription": "Collapse extra blank lines between paragraphs",
|
||||
"scrollAmount": "Scroll amount (screen height by default)",
|
||||
"showBatteryAndTime": "Battery & time",
|
||||
"showBatteryAndTimeDescription": "Show battery level and clock over the reading screen",
|
||||
"showProgressPercentage": "Reading progress",
|
||||
"showProgressPercentageDescription": "Show the percentage read at the bottom of the screen",
|
||||
"swipeGestures": "Swipe between chapters",
|
||||
"swipeGesturesDescription": "Swipe left or right to jump to the next or previous chapter",
|
||||
"textAlign": "Text alignment",
|
||||
"textSize": "文本大小",
|
||||
"ttsAutoPageAdvanceDescription": "Move to the next chapter automatically when narration ends",
|
||||
"ttsEngineDescription": "Text-to-speech engine used to generate audio",
|
||||
"ttsScrollToTopDescription": "Jump back to the top of the chapter when narration starts",
|
||||
"useChapterDrawerSwipeNavigation": "Swipe to open drawer",
|
||||
"verticalSeekbar": "Vertical seekbar",
|
||||
"verticalSeekbarDescription": "Show a slider on the side to jump to any point in the chapter",
|
||||
"keepScreenOn": "Keep screen on",
|
||||
"volumeButtonsScroll": "Volume button scrolling"
|
||||
"volumeButtonsScroll": "Volume button scrolling",
|
||||
"volumeButtonsScrollDescription": "Use the volume buttons to scroll instead of adjusting volume"
|
||||
},
|
||||
"drawer": {
|
||||
"scrollToBottom": "捲動至底",
|
||||
@@ -489,7 +598,9 @@
|
||||
"finished": "已完成",
|
||||
"nextChapter": "Next: %{name}",
|
||||
"noNextChapter": "没有下一章节",
|
||||
"noPreviousChapter": "There's no previous chapter"
|
||||
"noPreviousChapter": "There's no previous chapter",
|
||||
"searchMinLength": "Enter at least %{count} characters to search",
|
||||
"searchPlaceholder": "Search chapter"
|
||||
},
|
||||
"readerSettings": {
|
||||
"autoScrollInterval": "Scroll interval (seconds)",
|
||||
@@ -514,7 +625,8 @@
|
||||
"textColor": "文字颜色",
|
||||
"textColorModal": "Text color",
|
||||
"title": "阅读器",
|
||||
"verticalSeekbarDesc": "Use vertical seekbar"
|
||||
"verticalSeekbarDesc": "Use vertical seekbar",
|
||||
"volumeButtonOffset": "Volume button scroll offset (screen heights)"
|
||||
},
|
||||
"sourceScreen": {
|
||||
"noResultsFound": "未找到相应结果"
|
||||
@@ -528,10 +640,16 @@
|
||||
"title": "統計資料",
|
||||
"titlesInLibrary": "Titles in library",
|
||||
"totalChapters": "總章節",
|
||||
"unreadChapters": "未讀章節"
|
||||
"unreadChapters": "未讀章節",
|
||||
"topNovelsByTimeSpent": "Top novels by time spent",
|
||||
"topCategoriesByTimeSpent": "Top categories by time spent",
|
||||
"totalTimeSpent": "Total time spent",
|
||||
"showNovels": "Group by novel",
|
||||
"showCategories": "Group by category"
|
||||
},
|
||||
"tracking": "Tracking",
|
||||
"trackingScreen": {
|
||||
"info": "Tracking is one-way: reading progress is sent to external services. Link each novel individually using its tracking button.",
|
||||
"logOutMessage": "Log out from %{name}?",
|
||||
"revalidate": "Revalidate",
|
||||
"services": "Services"
|
||||
@@ -559,6 +677,7 @@
|
||||
},
|
||||
"notifications": {
|
||||
"IMPORT_EPUB": "Importing EPUB",
|
||||
"EXPORT_EPUB": "Exporting EPUB",
|
||||
"UPDATE_LIBRARY": "Updating Library",
|
||||
"DRIVE_BACKUP": "Google Drive Backup",
|
||||
"DRIVE_RESTORE": "Google Drive Restore",
|
||||
@@ -568,5 +687,23 @@
|
||||
"LOCAL_RESTORE": "Local Restore",
|
||||
"MIGRATE_NOVEL": "Migrating Novel",
|
||||
"DOWNLOAD_CHAPTER": "Downloading Chapter"
|
||||
},
|
||||
"time": {
|
||||
"seconds": {
|
||||
"one": "%{count} second",
|
||||
"other": "%{count} seconds"
|
||||
},
|
||||
"minutes": {
|
||||
"one": "%{count} minute",
|
||||
"other": "%{count} minutes"
|
||||
},
|
||||
"hours": {
|
||||
"one": "%{count} hour",
|
||||
"other": "%{count} hours"
|
||||
},
|
||||
"days": {
|
||||
"one": "%{count} day",
|
||||
"other": "%{count} days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +77,18 @@ export interface StringMap {
|
||||
'appearanceScreen.theme.yinyang': 'string';
|
||||
'backupScreen.backupName': 'string';
|
||||
'backupScreen.backupCreated': 'string';
|
||||
'backupScreen.backupCreatedWithWarnings': 'string';
|
||||
'backupScreen.backupRestored': 'string';
|
||||
'backupScreen.backupRestoredSelectedWithWarnings': 'string';
|
||||
'backupScreen.backupRestoredSummary.one': 'string';
|
||||
'backupScreen.backupRestoredSummary.other': 'string';
|
||||
'backupScreen.backupRestoredWithWarnings.one': 'string';
|
||||
'backupScreen.backupRestoredWithWarnings.other': 'string';
|
||||
'backupScreen.savingBackup': 'string';
|
||||
'backupScreen.categoriesRestored': 'string';
|
||||
'backupScreen.categoriesRestoredWithErrors': 'string';
|
||||
'backupScreen.categoriesRestoreFailedSummary.one': 'string';
|
||||
'backupScreen.categoriesRestoreFailedSummary.other': 'string';
|
||||
'backupScreen.categoryRestoreFailed': 'string';
|
||||
'backupScreen.categoryFileNotFound': 'string';
|
||||
'backupScreen.categoryFileReadFailed': 'string';
|
||||
@@ -93,14 +101,26 @@ export interface StringMap {
|
||||
'backupScreen.failed': 'string';
|
||||
'backupScreen.novelsRestored': 'string';
|
||||
'backupScreen.novelsRestoredWithErrors': 'string';
|
||||
'backupScreen.novelsBackupFailedSummary.one': 'string';
|
||||
'backupScreen.novelsBackupFailedSummary.other': 'string';
|
||||
'backupScreen.novelsRestoreFailedSummary.one': 'string';
|
||||
'backupScreen.novelsRestoreFailedSummary.other': 'string';
|
||||
'backupScreen.novelBackupFailed': 'string';
|
||||
'backupScreen.novelRestoreFailed': 'string';
|
||||
'backupScreen.novelDirectoryNotFound': 'string';
|
||||
'backupScreen.novelDirectoryReadFailed': 'string';
|
||||
'backupScreen.restoringCategories': 'string';
|
||||
'backupScreen.restoringCategoriesProgress': 'string';
|
||||
'backupScreen.restoringNovels': 'string';
|
||||
'backupScreen.restoringNovelsProgress': 'string';
|
||||
'backupScreen.restoringSettings': 'string';
|
||||
'backupScreen.missingPluginsAfterRestore': 'string';
|
||||
'backupScreen.sectionsRestoreFailedSummary.one': 'string';
|
||||
'backupScreen.sectionsRestoreFailedSummary.other': 'string';
|
||||
'backupScreen.sectionsBackupFailedSummary.one': 'string';
|
||||
'backupScreen.sectionsBackupFailedSummary.other': 'string';
|
||||
'backupScreen.settingsRestored': 'string';
|
||||
'backupScreen.settingsRestoreFailedSummary': 'string';
|
||||
'backupScreen.settingsFileNotFound': 'string';
|
||||
'backupScreen.settingsRestoreFailed': 'string';
|
||||
'backupScreen.settingsFileWriteFailed': 'string';
|
||||
@@ -115,7 +135,19 @@ export interface StringMap {
|
||||
'backupScreen.invalidBackupFolder': 'string';
|
||||
'backupScreen.localBackup': 'string';
|
||||
'backupScreen.noBackupFound': 'string';
|
||||
'backupScreen.options.title': 'string';
|
||||
'backupScreen.options.description': 'string';
|
||||
'backupScreen.options.selectAll': 'string';
|
||||
'backupScreen.options.library': 'string';
|
||||
'backupScreen.options.libraryDescription': 'string';
|
||||
'backupScreen.options.settings': 'string';
|
||||
'backupScreen.options.settingsDescription': 'string';
|
||||
'backupScreen.options.plugins': 'string';
|
||||
'backupScreen.options.pluginsDescription': 'string';
|
||||
'backupScreen.options.downloadedFiles': 'string';
|
||||
'backupScreen.options.downloadedFilesDescription': 'string';
|
||||
'backupScreen.preparingData': 'string';
|
||||
'backupScreen.preparingSelectedFiles': 'string';
|
||||
'backupScreen.remote.backup': 'string';
|
||||
'backupScreen.remote.host': 'string';
|
||||
'backupScreen.remote.unknownHost': 'string';
|
||||
@@ -125,9 +157,11 @@ export interface StringMap {
|
||||
'backupScreen.restoreLargeBackupsWarning': 'string';
|
||||
'backupScreen.restorinBackup': 'string';
|
||||
'backupScreen.restoringData': 'string';
|
||||
'backupScreen.restoringSelectedFiles': 'string';
|
||||
'backupScreen.selfHost': 'string';
|
||||
'backupScreen.selfHostDesc': 'string';
|
||||
'backupScreen.uploadingData': 'string';
|
||||
'backupScreen.uploadingSelectedFiles': 'string';
|
||||
'backupScreen.uploadingDownloadedFiles': 'string';
|
||||
'browse': 'string';
|
||||
'browseScreen.addedToLibrary': 'string';
|
||||
@@ -588,6 +622,9 @@ export interface StringMap {
|
||||
'notifications.LOCAL_RESTORE': 'string';
|
||||
'notifications.MIGRATE_NOVEL': 'string';
|
||||
'notifications.DOWNLOAD_CHAPTER': 'string';
|
||||
'notifications.taskQueued': 'string';
|
||||
'notifications.taskCompleted': 'string';
|
||||
'notifications.taskFailed': 'string';
|
||||
'time.seconds.one': 'string';
|
||||
'time.seconds.other': 'string';
|
||||
'time.minutes.one': 'string';
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { getMMKVObject, setMMKVObject } from '@utils/mmkv/mmkv';
|
||||
import {
|
||||
getPlugin,
|
||||
INSTALLED_PLUGINS_KEY,
|
||||
reloadInstalledPlugins,
|
||||
} from '../pluginManager';
|
||||
import type { PluginItem } from '../types';
|
||||
|
||||
jest.mock('@database/queries/RepositoryQueries', () => ({
|
||||
getRepositoriesFromDb: jest.fn().mockResolvedValue([]),
|
||||
}));
|
||||
|
||||
jest.mock('@noble/ciphers/aes.js', () => ({
|
||||
gcm: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@noble/ciphers/utils.js', () => ({
|
||||
bytesToUtf8: jest.fn(),
|
||||
utf8ToBytes: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('cheerio', () => ({
|
||||
load: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('htmlparser2', () => ({
|
||||
Parser: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@hooks/persisted/useUserAgent', () => ({
|
||||
getUserAgent: () => 'LNReader test',
|
||||
}));
|
||||
|
||||
jest.mock('@utils/mmkv/mmkv', () => ({
|
||||
getMMKVObject: jest.fn(),
|
||||
setMMKVObject: jest.fn(),
|
||||
}));
|
||||
|
||||
const restoredPlugins = [
|
||||
{ id: 'restored', name: 'Restored plugin' },
|
||||
{ id: 'invalid', name: 'Invalid plugin' },
|
||||
] as PluginItem[];
|
||||
|
||||
describe('reloadInstalledPlugins', () => {
|
||||
it('loads restored bundles and removes registry entries that cannot load', async () => {
|
||||
jest.mocked(getMMKVObject).mockReturnValueOnce(restoredPlugins);
|
||||
jest.mocked(NativeFile.readFile).mockImplementation(async path => {
|
||||
if (path.endsWith('/restored/index.js')) {
|
||||
return `exports.default = {
|
||||
id: 'restored',
|
||||
name: 'Restored plugin',
|
||||
version: '1.0.0',
|
||||
site: 'https://example.com'
|
||||
};`;
|
||||
}
|
||||
throw new Error('Missing plugin bundle');
|
||||
});
|
||||
|
||||
await expect(reloadInstalledPlugins()).resolves.toEqual(['invalid']);
|
||||
|
||||
expect(getPlugin('restored')).toMatchObject({
|
||||
id: 'restored',
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(getPlugin('invalid')).toBeUndefined();
|
||||
expect(setMMKVObject).toHaveBeenCalledWith(INSTALLED_PLUGINS_KEY, [
|
||||
restoredPlugins[0],
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -9,10 +9,10 @@ import { encode, decode } from 'urlencode';
|
||||
import { getRepositoriesFromDb } from '@database/queries/RepositoryQueries';
|
||||
import { getUserAgent } from '@hooks/persisted/useUserAgent';
|
||||
import { newer } from '@utils/compareVersion';
|
||||
import NativeFile from '@modules/native-file'
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { showToast } from '@utils/showToast';
|
||||
import { PLUGIN_STORAGE } from '@utils/Storages';
|
||||
import { getMMKVObject } from '@utils/mmkv/mmkv';
|
||||
import { getMMKVObject, setMMKVObject } from '@utils/mmkv/mmkv';
|
||||
|
||||
import {
|
||||
store,
|
||||
@@ -193,12 +193,38 @@ const initializeInstalledPlugins = async () => {
|
||||
await Promise.all(installedPlugins.map(plugin => loadPlugin(plugin.id)));
|
||||
};
|
||||
|
||||
const reloadInstalledPlugins = async (): Promise<string[]> => {
|
||||
const installedPlugins =
|
||||
getMMKVObject<PluginItem[]>(INSTALLED_PLUGINS_KEY) || [];
|
||||
|
||||
Object.keys(plugins).forEach(pluginId => {
|
||||
plugins[pluginId] = undefined;
|
||||
});
|
||||
|
||||
const results = await Promise.all(
|
||||
installedPlugins.map(async plugin => ({
|
||||
plugin,
|
||||
source: await loadPlugin(plugin.id),
|
||||
})),
|
||||
);
|
||||
const restoredPlugins = results
|
||||
.filter(result => result.source)
|
||||
.map(result => result.plugin);
|
||||
|
||||
setMMKVObject(INSTALLED_PLUGINS_KEY, restoredPlugins);
|
||||
|
||||
return results
|
||||
.filter(result => !result.source)
|
||||
.map(result => result.plugin.id);
|
||||
};
|
||||
|
||||
const LOCAL_PLUGIN_ID = 'local';
|
||||
|
||||
export {
|
||||
getPlugin,
|
||||
loadPlugin,
|
||||
initializeInstalledPlugins,
|
||||
reloadInstalledPlugins,
|
||||
installPlugin,
|
||||
uninstallPlugin,
|
||||
updatePlugin,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
createSqliteAdapter,
|
||||
classifySqlStatement,
|
||||
SqliteQueryResult,
|
||||
} from '@rozenite/sqlite-plugin';
|
||||
import { db } from '@database/db';
|
||||
|
||||
/**
|
||||
* Columns from op-sqlite's QueryResult may be undefined when the native layer
|
||||
* returns keyed rows directly. Always derive a usable column list, falling
|
||||
* back to the keys of the first row object.
|
||||
*/
|
||||
const deriveColumns = (
|
||||
columnNames: string[] | undefined,
|
||||
firstRow: Record<string, unknown> | undefined,
|
||||
): string[] => {
|
||||
if (columnNames && columnNames.length > 0) {
|
||||
return columnNames;
|
||||
}
|
||||
if (firstRow) {
|
||||
return Object.keys(firstRow);
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* op-sqlite's enhanced `execute` wrapper only reconstructs rows from rawRows
|
||||
* when `result.rows` is falsy — but an empty array `[]` is truthy in JS, so
|
||||
* the fallback is skipped. We handle the same reconstruction ourselves to
|
||||
* stay robust across all op-sqlite versions.
|
||||
*/
|
||||
const reconstructRows = (
|
||||
rows: unknown,
|
||||
rawRows: unknown,
|
||||
columnNames: string[] | undefined,
|
||||
): Record<string, unknown>[] => {
|
||||
if (Array.isArray(rows) && rows.length > 0) {
|
||||
return rows as Record<string, unknown>[];
|
||||
}
|
||||
|
||||
if (!Array.isArray(rawRows) || rawRows.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const cols = deriveColumns(columnNames, undefined);
|
||||
|
||||
if (cols.length === 0) {
|
||||
// No column info at all — return raw rows as value-only arrays
|
||||
return rawRows as unknown as Record<string, unknown>[];
|
||||
}
|
||||
|
||||
return rawRows.map((rawRow: unknown) => {
|
||||
const row: Record<string, unknown> = {};
|
||||
const values = rawRow as unknown[];
|
||||
for (let j = 0; j < cols.length; j++) {
|
||||
row[cols[j]!] = values[j];
|
||||
}
|
||||
return row;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Rozenite SQLite adapter for @op-engineering/op-sqlite.
|
||||
*
|
||||
* Gated to `__DEV__`; import and pass to `useRozeniteSqlitePlugin` only
|
||||
* during development builds.
|
||||
*/
|
||||
export const opSqliteAdapter = __DEV__
|
||||
? createSqliteAdapter({
|
||||
adapterId: 'op-sqlite',
|
||||
adapterName: 'OP SQLite',
|
||||
databases: {
|
||||
main: {
|
||||
name: 'lnreader.db',
|
||||
executeStatements: async statements => {
|
||||
const results: SqliteQueryResult[] = [];
|
||||
|
||||
for (const stmt of statements) {
|
||||
const start = performance.now();
|
||||
const result = await db.execute(
|
||||
stmt.sql,
|
||||
stmt.params as any[] | undefined,
|
||||
);
|
||||
const duration = performance.now() - start;
|
||||
|
||||
const rows = reconstructRows(
|
||||
result.rows,
|
||||
(result as any).rawRows,
|
||||
result.columnNames,
|
||||
);
|
||||
const columns = deriveColumns(result.columnNames, rows[0]);
|
||||
|
||||
results.push({
|
||||
rows,
|
||||
columns,
|
||||
metadata: {
|
||||
statementType: classifySqlStatement(stmt.sql),
|
||||
rowCount: rows.length,
|
||||
changes: result.rowsAffected ?? null,
|
||||
lastInsertRowId: result.insertId ?? null,
|
||||
durationMs: duration,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
: null;
|
||||
@@ -0,0 +1,171 @@
|
||||
import { useCallback } from 'react';
|
||||
import { ScrollView, StyleSheet, View } from 'react-native';
|
||||
|
||||
import { Checkbox } from '@components/Checkbox/Checkbox';
|
||||
import { Dialog } from '@components/Dialog';
|
||||
import { getString } from '@i18n/translations';
|
||||
import {
|
||||
areAllBackupOptionsSelected,
|
||||
hasSelectedBackupOption,
|
||||
type BackupOptions,
|
||||
} from '@services/backup/options';
|
||||
import type { ThemeColors } from '@theme/types';
|
||||
|
||||
type BackupOptionKey = keyof BackupOptions;
|
||||
|
||||
const OPTION_KEYS: BackupOptionKey[] = [
|
||||
'library',
|
||||
'settings',
|
||||
'plugins',
|
||||
'downloadedFiles',
|
||||
];
|
||||
|
||||
const OPTION_STRINGS: Record<
|
||||
BackupOptionKey,
|
||||
{
|
||||
description: Parameters<typeof getString>[0];
|
||||
label: Parameters<typeof getString>[0];
|
||||
}
|
||||
> = {
|
||||
library: {
|
||||
label: 'backupScreen.options.library',
|
||||
description: 'backupScreen.options.libraryDescription',
|
||||
},
|
||||
settings: {
|
||||
label: 'backupScreen.options.settings',
|
||||
description: 'backupScreen.options.settingsDescription',
|
||||
},
|
||||
plugins: {
|
||||
label: 'backupScreen.options.plugins',
|
||||
description: 'backupScreen.options.pluginsDescription',
|
||||
},
|
||||
downloadedFiles: {
|
||||
label: 'backupScreen.options.downloadedFiles',
|
||||
description: 'backupScreen.options.downloadedFilesDescription',
|
||||
},
|
||||
};
|
||||
|
||||
type BackupOptionsListProps = {
|
||||
options: BackupOptions;
|
||||
onChange: (options: BackupOptions) => void;
|
||||
theme: ThemeColors;
|
||||
};
|
||||
|
||||
export const BackupOptionsList = ({
|
||||
options,
|
||||
onChange,
|
||||
theme,
|
||||
}: BackupOptionsListProps) => {
|
||||
const allSelected = areAllBackupOptionsSelected(options);
|
||||
const someSelected = hasSelectedBackupOption(options);
|
||||
|
||||
const toggleAll = useCallback(() => {
|
||||
const selected = !allSelected;
|
||||
onChange({
|
||||
library: selected,
|
||||
settings: selected,
|
||||
plugins: selected,
|
||||
downloadedFiles: selected,
|
||||
});
|
||||
}, [allSelected, onChange]);
|
||||
|
||||
const toggleOption = useCallback(
|
||||
(key: BackupOptionKey) => {
|
||||
const selected = !options[key];
|
||||
onChange({
|
||||
...options,
|
||||
[key]: selected,
|
||||
...(key === 'library' && !selected
|
||||
? { downloadedFiles: false }
|
||||
: undefined),
|
||||
});
|
||||
},
|
||||
[onChange, options],
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog.ScrollArea>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
nestedScrollEnabled
|
||||
>
|
||||
<Checkbox
|
||||
label={getString('backupScreen.options.selectAll')}
|
||||
onPress={toggleAll}
|
||||
status={allSelected ? true : someSelected ? 'indeterminate' : false}
|
||||
theme={theme}
|
||||
/>
|
||||
<View
|
||||
style={[styles.divider, { backgroundColor: theme.outlineVariant }]}
|
||||
/>
|
||||
{OPTION_KEYS.map(key => {
|
||||
const disabled = key === 'downloadedFiles' && !options.library;
|
||||
const strings = OPTION_STRINGS[key];
|
||||
return (
|
||||
<Checkbox
|
||||
key={key}
|
||||
description={getString(strings.description)}
|
||||
disabled={disabled}
|
||||
label={getString(strings.label)}
|
||||
onPress={() => toggleOption(key)}
|
||||
status={options[key]}
|
||||
theme={theme}
|
||||
viewStyle={styles.option}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
</Dialog.ScrollArea>
|
||||
);
|
||||
};
|
||||
|
||||
type BackupOptionsDialogProps = BackupOptionsListProps & {
|
||||
visible: boolean;
|
||||
onCancel: () => void;
|
||||
onConfirm: () => void;
|
||||
};
|
||||
|
||||
export const BackupOptionsDialog = ({
|
||||
visible,
|
||||
options,
|
||||
onCancel,
|
||||
onChange,
|
||||
onConfirm,
|
||||
theme,
|
||||
}: BackupOptionsDialogProps) => (
|
||||
<Dialog.Root
|
||||
onDismiss={onCancel}
|
||||
testID="backup-options-dialog"
|
||||
visible={visible}
|
||||
>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{getString('backupScreen.options.title')}</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
{getString('backupScreen.options.description')}
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<BackupOptionsList onChange={onChange} options={options} theme={theme} />
|
||||
<Dialog.Actions>
|
||||
<Dialog.Action title={getString('common.cancel')} onPress={onCancel} />
|
||||
<Dialog.Action
|
||||
disabled={!hasSelectedBackupOption(options)}
|
||||
title={getString('common.backup')}
|
||||
onPress={onConfirm}
|
||||
/>
|
||||
</Dialog.Actions>
|
||||
</Dialog.Root>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
divider: {
|
||||
height: 1,
|
||||
marginVertical: 4,
|
||||
},
|
||||
option: {
|
||||
paddingVertical: 8,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
},
|
||||
});
|
||||
@@ -13,6 +13,12 @@ import { DriveFile } from '@api/drive/types';
|
||||
import { backgroundTasks } from '@services/backgroundTasks';
|
||||
import { useAppSettings } from '@hooks/persisted';
|
||||
import { formatDate } from '@utils/dateFormat';
|
||||
import {
|
||||
DEFAULT_BACKUP_OPTIONS,
|
||||
hasSelectedBackupOption,
|
||||
type BackupOptions,
|
||||
} from '@services/backup/options';
|
||||
import { BackupOptionsList } from './BackupOptions';
|
||||
|
||||
enum BackupModal {
|
||||
UNAUTHORIZED,
|
||||
@@ -98,6 +104,9 @@ function CreateBackup({
|
||||
}) {
|
||||
const [backupName, setBackupName] = useState('');
|
||||
const [fetching, setFetching] = useState(false);
|
||||
const [options, setOptions] = useState<BackupOptions>({
|
||||
...DEFAULT_BACKUP_OPTIONS,
|
||||
});
|
||||
|
||||
const prepare = async () => {
|
||||
setFetching(true);
|
||||
@@ -126,16 +135,28 @@ function CreateBackup({
|
||||
placeholderTextColor={theme.onSurfaceDisabled}
|
||||
disabled={fetching}
|
||||
/>
|
||||
<BackupOptionsList
|
||||
onChange={setOptions}
|
||||
options={options}
|
||||
theme={theme}
|
||||
/>
|
||||
<View style={styles.footerContainer}>
|
||||
<Button
|
||||
disabled={backupName.trim().length === 0 || fetching}
|
||||
disabled={
|
||||
backupName.trim().length === 0 ||
|
||||
fetching ||
|
||||
!hasSelectedBackupOption(options)
|
||||
}
|
||||
title={getString('common.ok')}
|
||||
onPress={() => {
|
||||
prepare().then(folder => {
|
||||
closeModal();
|
||||
backgroundTasks.enqueue({
|
||||
name: 'DRIVE_BACKUP',
|
||||
data: folder,
|
||||
data: {
|
||||
backupFolder: folder,
|
||||
options,
|
||||
},
|
||||
});
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -9,6 +9,12 @@ import { useCallback, useEffect, useState } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { TextInput } from 'react-native-paper';
|
||||
import {
|
||||
DEFAULT_BACKUP_OPTIONS,
|
||||
hasSelectedBackupOption,
|
||||
type BackupOptions,
|
||||
} from '@services/backup/options';
|
||||
import { BackupOptionsList } from './BackupOptions';
|
||||
|
||||
enum BackupModal {
|
||||
SET_HOST,
|
||||
@@ -35,6 +41,9 @@ function CreateBackup({
|
||||
closeModal: () => void;
|
||||
}) {
|
||||
const [backupName, setBackupName] = useState('');
|
||||
const [options, setOptions] = useState<BackupOptions>({
|
||||
...DEFAULT_BACKUP_OPTIONS,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -47,9 +56,16 @@ function CreateBackup({
|
||||
theme={{ colors: { ...theme } }}
|
||||
placeholderTextColor={theme.onSurfaceDisabled}
|
||||
/>
|
||||
<BackupOptionsList
|
||||
onChange={setOptions}
|
||||
options={options}
|
||||
theme={theme}
|
||||
/>
|
||||
<View style={styles.footerContainer}>
|
||||
<Button
|
||||
disabled={backupName.trim().length === 0}
|
||||
disabled={
|
||||
backupName.trim().length === 0 || !hasSelectedBackupOption(options)
|
||||
}
|
||||
title={getString('common.ok')}
|
||||
onPress={() => {
|
||||
closeModal();
|
||||
@@ -58,6 +74,7 @@ function CreateBackup({
|
||||
data: {
|
||||
host,
|
||||
backupFolder: backupName + '.backup',
|
||||
options,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react-native';
|
||||
|
||||
import type { BackupOptions } from '@services/backup/options';
|
||||
import type { ThemeColors } from '@theme/types';
|
||||
import { BackupOptionsList } from '../BackupOptions';
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
getString: (key: string) => key,
|
||||
}));
|
||||
|
||||
jest.mock('@hooks/persisted', () => ({
|
||||
useTheme: () => mockTheme,
|
||||
}));
|
||||
|
||||
const mockTheme = {
|
||||
onSurface: '#111111',
|
||||
onSurfaceDisabled: '#777777',
|
||||
onSurfaceVariant: '#555555',
|
||||
outlineVariant: '#cccccc',
|
||||
primary: '#6200ee',
|
||||
rippleColor: '#eeeeee',
|
||||
} as ThemeColors;
|
||||
|
||||
const allSelected: BackupOptions = {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: true,
|
||||
};
|
||||
|
||||
describe('BackupOptionsList', () => {
|
||||
it('supports selecting and clearing every backup section', () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
<BackupOptionsList
|
||||
onChange={onChange}
|
||||
options={allSelected}
|
||||
theme={mockTheme}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.press(
|
||||
screen.getByRole('checkbox', {
|
||||
name: 'backupScreen.options.selectAll',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
library: false,
|
||||
settings: false,
|
||||
plugins: false,
|
||||
downloadedFiles: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('clears downloaded files when library data is deselected', () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
<BackupOptionsList
|
||||
onChange={onChange}
|
||||
options={allSelected}
|
||||
theme={mockTheme}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.press(
|
||||
screen.getByRole('checkbox', {
|
||||
name: 'backupScreen.options.library',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
library: false,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('disables downloaded files when library data is not selected', () => {
|
||||
render(
|
||||
<BackupOptionsList
|
||||
onChange={() => {}}
|
||||
options={{
|
||||
...allSelected,
|
||||
library: false,
|
||||
downloadedFiles: false,
|
||||
}}
|
||||
theme={mockTheme}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByRole('checkbox', {
|
||||
name: 'backupScreen.options.downloadedFiles',
|
||||
}),
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
@@ -10,16 +10,36 @@ import { getString } from '@i18n/translations';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import dayjs from 'dayjs';
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
DEFAULT_BACKUP_OPTIONS,
|
||||
type BackupOptions,
|
||||
} from '@services/backup/options';
|
||||
import { BackupOptionsDialog } from './Components/BackupOptions';
|
||||
|
||||
const BackupSettings = ({ navigation }: BackupSettingsScreenProps) => {
|
||||
const theme = useTheme();
|
||||
const [backupOptions, setBackupOptions] = useState<BackupOptions>({
|
||||
...DEFAULT_BACKUP_OPTIONS,
|
||||
});
|
||||
const {
|
||||
value: backupOptionsVisible,
|
||||
setFalse: closeBackupOptions,
|
||||
setTrue: openBackupOptions,
|
||||
} = useBoolean();
|
||||
const {
|
||||
value: googleDriveModalVisible,
|
||||
setFalse: closeGoogleDriveModal,
|
||||
setTrue: openGoogleDriveModal,
|
||||
} = useBoolean();
|
||||
|
||||
const createLocalBackup = async () => {
|
||||
const createLocalBackup = () => {
|
||||
setBackupOptions({ ...DEFAULT_BACKUP_OPTIONS });
|
||||
openBackupOptions();
|
||||
};
|
||||
|
||||
const chooseLocalBackupDestination = async () => {
|
||||
closeBackupOptions();
|
||||
try {
|
||||
const filename = `lnreader_backup_${dayjs().format(
|
||||
'YYYY-MM-DD_HH_mm',
|
||||
@@ -30,7 +50,7 @@ const BackupSettings = ({ navigation }: BackupSettingsScreenProps) => {
|
||||
);
|
||||
backgroundTasks.enqueue({
|
||||
name: 'LOCAL_BACKUP',
|
||||
data: { destinationUri },
|
||||
data: { destinationUri, options: backupOptions },
|
||||
});
|
||||
} catch {
|
||||
// Closing Android's document picker intentionally leaves the queue unchanged.
|
||||
@@ -115,6 +135,14 @@ const BackupSettings = ({ navigation }: BackupSettingsScreenProps) => {
|
||||
visible={selfHostModalVisible}
|
||||
closeModal={closeSelfHostModal}
|
||||
/>
|
||||
<BackupOptionsDialog
|
||||
onCancel={closeBackupOptions}
|
||||
onChange={setBackupOptions}
|
||||
onConfirm={chooseLocalBackupDestination}
|
||||
options={backupOptions}
|
||||
theme={theme}
|
||||
visible={backupOptionsVisible}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,17 +10,14 @@ import {
|
||||
updateRepository,
|
||||
} from '@database/queries/RepositoryQueries';
|
||||
import { Repository } from '@database/types';
|
||||
import { useBackHandler, useBoolean } from '@hooks/index';
|
||||
import { useBoolean } from '@hooks/index';
|
||||
import { usePluginActions, useTheme } from '@hooks/persisted';
|
||||
import { getString } from '@i18n/translations';
|
||||
|
||||
import AddRepositoryModal from './components/AddRepositoryModal';
|
||||
import RepositoryCard from './components/RepositoryCard';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import {
|
||||
RespositorySettingsScreenProps,
|
||||
RootStackParamList,
|
||||
} from '@navigators/types';
|
||||
import { RespositorySettingsScreenProps } from '@navigators/types';
|
||||
import { showToast } from '@utils/showToast';
|
||||
import { useLiveQuery } from '@database/manager/liveQuery';
|
||||
import { repositorySchema } from '@database/schema';
|
||||
@@ -73,14 +70,6 @@ const SettingsBrowseScreen = ({
|
||||
}
|
||||
}, [params, upsertRepository]);
|
||||
|
||||
useBackHandler(() => {
|
||||
if (!navigation.canGoBack()) {
|
||||
navigation.popTo<keyof RootStackParamList>('BottomNavigator');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<SafeAreaView excludeTop>
|
||||
<Appbar
|
||||
@@ -89,7 +78,6 @@ const SettingsBrowseScreen = ({
|
||||
if (navigation.canGoBack()) {
|
||||
navigation.goBack();
|
||||
}
|
||||
navigation.popTo<keyof RootStackParamList>('BottomNavigator');
|
||||
}}
|
||||
theme={theme}
|
||||
/>
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
allowsDuplicateTask,
|
||||
createBackgroundTaskMetadata,
|
||||
fromNativeTaskRecord,
|
||||
getBackgroundTaskQueueName,
|
||||
willTaskWaitInQueue,
|
||||
} from './taskDefinitions';
|
||||
import { BACKGROUND_TASKS_STORE_KEY } from './constants';
|
||||
|
||||
@@ -23,7 +25,6 @@ const makeTemporaryId = () =>
|
||||
`pending-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||
|
||||
export class BackgroundTaskQueue {
|
||||
private currentTaskId?: string;
|
||||
private interruptedTasks = new Map<string, 'pause' | 'cancel'>();
|
||||
private notificationPermissionRequest?: Promise<boolean>;
|
||||
|
||||
@@ -59,7 +60,13 @@ export class BackgroundTaskQueue {
|
||||
|
||||
enqueue = (tasks: BackgroundTask | BackgroundTask[]) => {
|
||||
for (const task of Array.isArray(tasks) ? tasks : [tasks]) {
|
||||
this.enqueueOne(task).catch(() => undefined);
|
||||
this.enqueueOne(task, true).catch(() => undefined);
|
||||
}
|
||||
};
|
||||
|
||||
private enqueueSilently = (tasks: BackgroundTask | BackgroundTask[]) => {
|
||||
for (const task of Array.isArray(tasks) ? tasks : [tasks]) {
|
||||
this.enqueueOne(task, false).catch(() => undefined);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -100,7 +107,6 @@ export class BackgroundTaskQueue {
|
||||
}
|
||||
|
||||
async run(taskId: string, task: BackgroundTask, checkpoint?: string) {
|
||||
this.currentTaskId = taskId;
|
||||
const queue = this.getSnapshot();
|
||||
if (!queue.some(item => item.id === taskId)) {
|
||||
queue.push({
|
||||
@@ -115,8 +121,8 @@ export class BackgroundTaskQueue {
|
||||
try {
|
||||
await executeBackgroundTask(
|
||||
task,
|
||||
this.updateProgress.bind(this),
|
||||
this.enqueue,
|
||||
transformer => this.updateProgress(taskId, transformer),
|
||||
this.enqueueSilently,
|
||||
{
|
||||
checkpoint,
|
||||
updateCheckpoint: value => {
|
||||
@@ -128,9 +134,20 @@ export class BackgroundTaskQueue {
|
||||
},
|
||||
);
|
||||
this.throwIfInterrupted(taskId);
|
||||
await NativeBackgroundTasks.complete(taskId);
|
||||
const completedTask = this.getSnapshot().find(item => item.id === taskId);
|
||||
await NativeBackgroundTasks.complete(
|
||||
taskId,
|
||||
completedTask?.meta.completionText ??
|
||||
getString('notifications.taskCompleted'),
|
||||
);
|
||||
} catch (error) {
|
||||
await NativeBackgroundTasks.fail(taskId, String(error), false);
|
||||
await NativeBackgroundTasks.fail(
|
||||
taskId,
|
||||
getString('notifications.taskFailed', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
}),
|
||||
false,
|
||||
);
|
||||
if (!this.interruptedTasks.has(taskId)) {
|
||||
throw error;
|
||||
}
|
||||
@@ -139,7 +156,7 @@ export class BackgroundTaskQueue {
|
||||
}
|
||||
}
|
||||
|
||||
private async enqueueOne(task: BackgroundTask) {
|
||||
private async enqueueOne(task: BackgroundTask, showQueuedToast: boolean) {
|
||||
this.notificationPermissionRequest ??= askForPostNotificationsPermission();
|
||||
await this.notificationPermissionRequest;
|
||||
|
||||
@@ -157,6 +174,8 @@ export class BackgroundTaskQueue {
|
||||
state: 'queued',
|
||||
meta: createBackgroundTaskMetadata(task, false),
|
||||
};
|
||||
const shouldShowQueuedToast =
|
||||
showQueuedToast && willTaskWaitInQueue(task, current);
|
||||
this.store([...current, pending]);
|
||||
|
||||
try {
|
||||
@@ -166,12 +185,18 @@ export class BackgroundTaskQueue {
|
||||
pending.meta.name,
|
||||
pending.meta.progressText || getString('common.preparing'),
|
||||
allowsDuplicateTask(task),
|
||||
getBackgroundTaskQueueName(task),
|
||||
);
|
||||
const latest = this.getSnapshot().filter(item => item.id !== pending.id);
|
||||
if (!latest.some(item => item.id === id)) {
|
||||
latest.push({ ...pending, id });
|
||||
}
|
||||
this.store(latest);
|
||||
if (shouldShowQueuedToast) {
|
||||
showToast(
|
||||
getString('notifications.taskQueued', { task: pending.meta.name }),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.store(this.getSnapshot().filter(item => item.id !== pending.id));
|
||||
showToast(
|
||||
@@ -183,10 +208,9 @@ export class BackgroundTaskQueue {
|
||||
}
|
||||
|
||||
private updateProgress(
|
||||
taskId: string,
|
||||
transformer: (meta: BackgroundTaskMetadata) => BackgroundTaskMetadata,
|
||||
) {
|
||||
const taskId = this.currentTaskId;
|
||||
if (!taskId) return;
|
||||
this.throwIfInterrupted(taskId);
|
||||
|
||||
const queue = this.getSnapshot();
|
||||
@@ -224,7 +248,6 @@ export class BackgroundTaskQueue {
|
||||
} else {
|
||||
this.store(this.getSnapshot().filter(item => item.id !== taskId));
|
||||
}
|
||||
this.currentTaskId = undefined;
|
||||
this.interruptedTasks.delete(taskId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
import NativeBackgroundTasks from '@modules/native-background-tasks';
|
||||
import { showToast } from '@utils/showToast';
|
||||
import { BackgroundTaskQueue } from '../BackgroundTaskQueue';
|
||||
import { executeBackgroundTask } from '../executeTask';
|
||||
|
||||
let mockStoredTasks: unknown[] = [];
|
||||
|
||||
jest.mock('@modules/native-background-tasks', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
complete: jest.fn(),
|
||||
enqueue: jest.fn().mockResolvedValue('native-task-1'),
|
||||
fail: jest.fn(),
|
||||
updateProgress: jest.fn().mockResolvedValue(undefined),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../executeTask', () => ({
|
||||
executeBackgroundTask: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/askForPostNoftificationsPermission', () => ({
|
||||
askForPostNotificationsPermission: jest.fn().mockResolvedValue(true),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/mmkv/mmkv', () => ({
|
||||
getMMKVObject: jest.fn(() => mockStoredTasks),
|
||||
setMMKVObject: jest.fn((_key: string, value: unknown[]) => {
|
||||
mockStoredTasks = value;
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
getString: (key: string, options?: Record<string, string>) =>
|
||||
key === 'notifications.taskFailed'
|
||||
? `Failed: ${options?.error}`
|
||||
: key === 'notifications.taskQueued'
|
||||
? `${options?.task} queued`
|
||||
: key === 'notifications.LOCAL_RESTORE'
|
||||
? 'Local restore'
|
||||
: key === 'notifications.DOWNLOAD_CHAPTER'
|
||||
? 'Download'
|
||||
: key === 'common.preparing'
|
||||
? 'Preparing'
|
||||
: 'Completed',
|
||||
}));
|
||||
|
||||
jest.mock('@utils/showToast', () => ({
|
||||
showToast: jest.fn(),
|
||||
}));
|
||||
|
||||
const task = {
|
||||
name: 'LOCAL_RESTORE' as const,
|
||||
data: { sourceUri: 'file://backup.zip' },
|
||||
};
|
||||
|
||||
describe('BackgroundTaskQueue completion notifications', () => {
|
||||
beforeEach(() => {
|
||||
mockStoredTasks = [];
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('passes a task-provided completion summary to the native notification', async () => {
|
||||
jest
|
||||
.mocked(executeBackgroundTask)
|
||||
.mockImplementation(async (_task, updateProgress) => {
|
||||
updateProgress(meta => ({
|
||||
...meta,
|
||||
completionText: 'Backup restored with warnings',
|
||||
}));
|
||||
});
|
||||
|
||||
await new BackgroundTaskQueue().run('restore-1', task);
|
||||
|
||||
expect(NativeBackgroundTasks.complete).toHaveBeenCalledWith(
|
||||
'restore-1',
|
||||
'Backup restored with warnings',
|
||||
);
|
||||
});
|
||||
|
||||
it('localizes failure text before handing it to the native notification', async () => {
|
||||
jest
|
||||
.mocked(executeBackgroundTask)
|
||||
.mockRejectedValueOnce(new Error('Invalid backup'));
|
||||
|
||||
await expect(
|
||||
new BackgroundTaskQueue().run('restore-2', task),
|
||||
).rejects.toThrow('Invalid backup');
|
||||
expect(NativeBackgroundTasks.fail).toHaveBeenCalledWith(
|
||||
'restore-2',
|
||||
'Failed: Invalid backup',
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('shows queued feedback when the task must wait in its lane', async () => {
|
||||
const downloadTask = {
|
||||
name: 'DOWNLOAD_CHAPTER' as const,
|
||||
data: {
|
||||
novelName: 'Example Novel',
|
||||
novelId: 42,
|
||||
pluginId: 'source-a',
|
||||
chapters: [{ chapterId: 7, chapterName: 'Chapter 7' }],
|
||||
},
|
||||
};
|
||||
mockStoredTasks = [
|
||||
{
|
||||
id: 'existing-task',
|
||||
task: downloadTask,
|
||||
state: 'running',
|
||||
meta: {
|
||||
name: 'Download: Example Novel',
|
||||
isRunning: true,
|
||||
progress: undefined,
|
||||
progressText: undefined,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
new BackgroundTaskQueue().enqueue(downloadTask);
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(NativeBackgroundTasks.enqueue).toHaveBeenCalledWith(
|
||||
downloadTask.name,
|
||||
JSON.stringify(downloadTask),
|
||||
'Download: Example Novel',
|
||||
'Chapter 7',
|
||||
true,
|
||||
'lnreader-background-task:download:source-a',
|
||||
);
|
||||
expect(showToast).toHaveBeenCalledWith('Download: Example Novel queued');
|
||||
});
|
||||
|
||||
it('does not show queued feedback when the task can start immediately', async () => {
|
||||
new BackgroundTaskQueue().enqueue(task);
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(NativeBackgroundTasks.enqueue).toHaveBeenCalled();
|
||||
expect(showToast).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps progress updates scoped to concurrently running tasks', async () => {
|
||||
const firstTask = {
|
||||
name: 'LOCAL_RESTORE' as const,
|
||||
data: { sourceUri: 'file://first.zip' },
|
||||
};
|
||||
const secondTask = {
|
||||
name: 'LOCAL_RESTORE' as const,
|
||||
data: { sourceUri: 'file://second.zip' },
|
||||
};
|
||||
const resolvers: (() => void)[] = [];
|
||||
|
||||
jest
|
||||
.mocked(executeBackgroundTask)
|
||||
.mockImplementation(async (runningTask, updateProgress) => {
|
||||
if (runningTask.name !== 'LOCAL_RESTORE') {
|
||||
throw new Error('Unexpected task type');
|
||||
}
|
||||
updateProgress(meta => ({
|
||||
...meta,
|
||||
progressText: runningTask.data.sourceUri,
|
||||
}));
|
||||
await new Promise<void>(resolve => resolvers.push(resolve));
|
||||
});
|
||||
|
||||
const firstRun = new BackgroundTaskQueue().run('first', firstTask);
|
||||
const secondRun = new BackgroundTaskQueue().run('second', secondTask);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(NativeBackgroundTasks.updateProgress).toHaveBeenCalledWith(
|
||||
'first',
|
||||
-1,
|
||||
'file://first.zip',
|
||||
);
|
||||
expect(NativeBackgroundTasks.updateProgress).toHaveBeenCalledWith(
|
||||
'second',
|
||||
-1,
|
||||
'file://second.zip',
|
||||
);
|
||||
|
||||
resolvers.forEach(resolve => resolve());
|
||||
await Promise.all([firstRun, secondRun]);
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,9 @@ import {
|
||||
allowsDuplicateTask,
|
||||
createBackgroundTaskMetadata,
|
||||
fromNativeTaskRecord,
|
||||
getBackgroundTaskQueueName,
|
||||
getBackgroundTaskTitle,
|
||||
willTaskWaitInQueue,
|
||||
} from '../taskDefinitions';
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
@@ -32,6 +34,7 @@ describe('background task definitions', () => {
|
||||
data: {
|
||||
novelName: 'Example Novel',
|
||||
novelId: 42,
|
||||
pluginId: 'source-a',
|
||||
chapters: [{ chapterId: 42, chapterName: 'Chapter 7' }],
|
||||
},
|
||||
};
|
||||
@@ -47,6 +50,65 @@ describe('background task definitions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('serializes downloads from one plugin but separates other plugin lanes', () => {
|
||||
const createDownload = (pluginId: string): BackgroundTask => ({
|
||||
name: 'DOWNLOAD_CHAPTER',
|
||||
data: {
|
||||
novelName: 'Example Novel',
|
||||
novelId: 42,
|
||||
pluginId,
|
||||
chapters: [{ chapterId: 42, chapterName: 'Chapter 7' }],
|
||||
},
|
||||
});
|
||||
|
||||
expect(getBackgroundTaskQueueName(createDownload('source-a'))).toBe(
|
||||
getBackgroundTaskQueueName(createDownload('source-a')),
|
||||
);
|
||||
expect(getBackgroundTaskQueueName(createDownload('source-a'))).not.toBe(
|
||||
getBackgroundTaskQueueName(createDownload('source-b')),
|
||||
);
|
||||
});
|
||||
|
||||
it('uses independent lanes for different non-download task types', () => {
|
||||
expect(getBackgroundTaskQueueName({ name: 'UPDATE_LIBRARY' })).not.toBe(
|
||||
getBackgroundTaskQueueName({
|
||||
name: 'LOCAL_RESTORE',
|
||||
data: { sourceUri: 'file://backup.zip' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('only reports queueing when a lane or the global limit blocks a task', () => {
|
||||
const createDownload = (pluginId: string): BackgroundTask => ({
|
||||
name: 'DOWNLOAD_CHAPTER',
|
||||
data: {
|
||||
novelName: pluginId,
|
||||
pluginId,
|
||||
chapters: [{ chapterId: 42, chapterName: 'Chapter 7' }],
|
||||
},
|
||||
});
|
||||
const queuedDownload = (pluginId: string) => ({
|
||||
id: pluginId,
|
||||
task: createDownload(pluginId),
|
||||
state: 'queued' as const,
|
||||
meta: createBackgroundTaskMetadata(createDownload(pluginId), false),
|
||||
});
|
||||
|
||||
expect(willTaskWaitInQueue(createDownload('source-a'), [])).toBe(false);
|
||||
expect(
|
||||
willTaskWaitInQueue(createDownload('source-a'), [
|
||||
queuedDownload('source-a'),
|
||||
]),
|
||||
).toBe(true);
|
||||
expect(
|
||||
willTaskWaitInQueue(createDownload('source-d'), [
|
||||
queuedDownload('source-a'),
|
||||
queuedDownload('source-b'),
|
||||
queuedDownload('source-c'),
|
||||
]),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('derives metadata for a multi-file EPUB import', () => {
|
||||
const task: BackgroundTask = {
|
||||
name: 'IMPORT_EPUB',
|
||||
|
||||
@@ -5,12 +5,21 @@ import type {
|
||||
EpubExportChapter,
|
||||
EpubExportMetadata,
|
||||
} from '@modules/nitro-epub';
|
||||
import type { BackupOptions } from '@services/backup/options';
|
||||
|
||||
export type SelfHostData = {
|
||||
host: string;
|
||||
backupFolder: string;
|
||||
options?: BackupOptions;
|
||||
};
|
||||
|
||||
export type DriveBackupData =
|
||||
| DriveFile
|
||||
| {
|
||||
backupFolder: DriveFile;
|
||||
options?: BackupOptions;
|
||||
};
|
||||
|
||||
export type MigrationNovelPreference = 'current' | 'destination';
|
||||
|
||||
export type MigrationNovelOptions = {
|
||||
@@ -55,11 +64,14 @@ export type BackgroundTask =
|
||||
name: 'UPDATE_LIBRARY';
|
||||
data?: { categoryId?: number; categoryName?: string };
|
||||
}
|
||||
| { name: 'DRIVE_BACKUP'; data: DriveFile }
|
||||
| { name: 'DRIVE_BACKUP'; data: DriveBackupData }
|
||||
| { name: 'DRIVE_RESTORE'; data: DriveFile }
|
||||
| { name: 'SELF_HOST_BACKUP'; data: SelfHostData }
|
||||
| { name: 'SELF_HOST_RESTORE'; data: SelfHostData }
|
||||
| { name: 'LOCAL_BACKUP'; data: { destinationUri: string } }
|
||||
| {
|
||||
name: 'LOCAL_BACKUP';
|
||||
data: { destinationUri: string; options?: BackupOptions };
|
||||
}
|
||||
| { name: 'LOCAL_RESTORE'; data: { sourceUri: string } }
|
||||
| { name: 'MIGRATE_NOVEL'; data: MigrateNovelData }
|
||||
| DownloadChapterTask;
|
||||
@@ -68,6 +80,11 @@ export type DownloadChapterTask = {
|
||||
name: 'DOWNLOAD_CHAPTER';
|
||||
data: {
|
||||
novelName: string;
|
||||
/**
|
||||
* Optional for compatibility with download tasks queued before
|
||||
* per-plugin execution lanes were introduced.
|
||||
*/
|
||||
pluginId?: string;
|
||||
/**
|
||||
* Optional for compatibility with download tasks persisted before the
|
||||
* per-novel queue identity was introduced.
|
||||
@@ -82,6 +99,7 @@ export type BackgroundTaskMetadata = {
|
||||
isRunning: boolean;
|
||||
progress: number | undefined;
|
||||
progressText: string | undefined;
|
||||
completionText?: string;
|
||||
};
|
||||
|
||||
export type TaskProgressUpdater = (
|
||||
|
||||
@@ -19,9 +19,48 @@ const MULTIPLICABLE_TASKS: BackgroundTask['name'][] = [
|
||||
'MIGRATE_NOVEL',
|
||||
];
|
||||
|
||||
const BACKGROUND_TASK_QUEUE_PREFIX = 'lnreader-background-task';
|
||||
const MAX_CONCURRENT_DOWNLOADS = 3;
|
||||
|
||||
export const allowsDuplicateTask = (task: BackgroundTask) =>
|
||||
MULTIPLICABLE_TASKS.includes(task.name);
|
||||
|
||||
export const getBackgroundTaskQueueName = (task: BackgroundTask) =>
|
||||
task.name === 'DOWNLOAD_CHAPTER'
|
||||
? `${BACKGROUND_TASK_QUEUE_PREFIX}:download:${
|
||||
task.data.pluginId || 'legacy'
|
||||
}`
|
||||
: `${BACKGROUND_TASK_QUEUE_PREFIX}:task:${task.name}`;
|
||||
|
||||
export const willTaskWaitInQueue = (
|
||||
task: BackgroundTask,
|
||||
activeTasks: QueuedBackgroundTask[],
|
||||
) => {
|
||||
const queueName = getBackgroundTaskQueueName(task);
|
||||
if (
|
||||
activeTasks.some(
|
||||
activeTask => getBackgroundTaskQueueName(activeTask.task) === queueName,
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (task.name !== 'DOWNLOAD_CHAPTER') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const activeDownloadLanes = new Set(
|
||||
activeTasks
|
||||
.filter(
|
||||
activeTask =>
|
||||
activeTask.task.name === 'DOWNLOAD_CHAPTER' &&
|
||||
activeTask.state !== 'paused',
|
||||
)
|
||||
.map(activeTask => getBackgroundTaskQueueName(activeTask.task)),
|
||||
);
|
||||
return activeDownloadLanes.size >= MAX_CONCURRENT_DOWNLOADS;
|
||||
};
|
||||
|
||||
export const getBackgroundTaskTitle = (task: BackgroundTask) => {
|
||||
switch (task.name) {
|
||||
case 'DOWNLOAD_CHAPTER':
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { getBackupCompletionText, type BackupResult } from '../backupResult';
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
getString: (key: string, options?: Record<string, string | number>) => {
|
||||
const strings: Record<string, string> = {
|
||||
'backupScreen.backupCreated': 'Backup created successfully',
|
||||
'backupScreen.backupCreatedWithWarnings':
|
||||
'Backup created with warnings: %{warnings}',
|
||||
};
|
||||
const pluralStrings: Record<string, [string, string]> = {
|
||||
'backupScreen.novelsBackupFailedSummary': [
|
||||
'%{count} novel failed',
|
||||
'%{count} novels failed',
|
||||
],
|
||||
'backupScreen.sectionsBackupFailedSummary': [
|
||||
'%{count} backup section failed',
|
||||
'%{count} backup sections failed',
|
||||
],
|
||||
};
|
||||
const pluralString = pluralStrings[key];
|
||||
const template = pluralString
|
||||
? pluralString[options?.count === 1 ? 0 : 1]
|
||||
: strings[key] ?? key;
|
||||
|
||||
return Object.entries(options ?? {}).reduce(
|
||||
(text, [name, value]) => text.replace(`%{${name}}`, String(value)),
|
||||
template,
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
describe('backup result notifications', () => {
|
||||
it('uses a concise success message when every section is backed up', () => {
|
||||
const result: BackupResult = {
|
||||
failedNovelCount: 0,
|
||||
failedSectionCount: 0,
|
||||
};
|
||||
|
||||
expect(getBackupCompletionText(result)).toBe('Backup created successfully');
|
||||
});
|
||||
|
||||
it('aggregates partial backup failures', () => {
|
||||
expect(
|
||||
getBackupCompletionText({
|
||||
failedNovelCount: 2,
|
||||
failedSectionCount: 1,
|
||||
}),
|
||||
).toBe(
|
||||
'Backup created with warnings: 2 novels failed; 1 backup section failed',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
import NativeFile from '@modules/native-file';
|
||||
import NativeZipArchive from '@modules/native-zip-archive';
|
||||
import { createBackup, restoreBackup } from '../local';
|
||||
import { finalizeRestoredPlugins } from '../restoreResult';
|
||||
import { prepareBackupData, restoreData } from '../utils';
|
||||
|
||||
jest.mock('../utils', () => ({
|
||||
CACHE_DIR_PATH: '/cache/BackupData',
|
||||
clearBackupCache: jest.fn(),
|
||||
prepareBackupData: jest.fn(),
|
||||
restoreData: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../restoreResult', () => ({
|
||||
finalizeRestoredPlugins: jest.fn(),
|
||||
getRestoreCompletionText: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../backupResult', () => ({
|
||||
getBackupCompletionText: jest.fn(() => 'Backup created'),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/Storages', () => ({
|
||||
NOVEL_STORAGE: '/storage/Novels',
|
||||
PLUGIN_STORAGE: '/storage/Plugins',
|
||||
ROOT_STORAGE: '/storage',
|
||||
}));
|
||||
|
||||
jest.mock('@utils/sleep', () => ({
|
||||
sleep: jest.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
getString: (key: string) => key,
|
||||
}));
|
||||
|
||||
describe('local selective backup', () => {
|
||||
it('creates archives only for selected file sections', async () => {
|
||||
jest.mocked(prepareBackupData).mockResolvedValue({
|
||||
failedNovelCount: 0,
|
||||
failedSectionCount: 0,
|
||||
});
|
||||
jest.mocked(NativeZipArchive.zip).mockResolvedValue(undefined);
|
||||
jest.mocked(NativeFile.copyFile).mockResolvedValue(undefined);
|
||||
|
||||
await createBackup({
|
||||
destinationUri: 'content://backup.zip',
|
||||
options: {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(prepareBackupData).toHaveBeenCalledWith('/cache/BackupData', {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: false,
|
||||
});
|
||||
expect(NativeZipArchive.zip).toHaveBeenCalledWith(
|
||||
'/storage/Plugins',
|
||||
'/cache/BackupData/plugins.zip',
|
||||
);
|
||||
expect(NativeZipArchive.zip).not.toHaveBeenCalledWith(
|
||||
'/storage/Novels',
|
||||
expect.any(String),
|
||||
);
|
||||
expect(NativeZipArchive.zip).toHaveBeenCalledWith(
|
||||
'/cache/BackupData',
|
||||
'/cache/BackupData.zip',
|
||||
);
|
||||
});
|
||||
|
||||
it('loads restored plugins after their archive is extracted', async () => {
|
||||
const restoreResult = {
|
||||
novelCount: 1,
|
||||
failedNovelCount: 0,
|
||||
categoryCount: 0,
|
||||
failedCategoryCount: 0,
|
||||
settingsRestored: true,
|
||||
failedSectionCount: 0,
|
||||
pluginIds: ['restored'],
|
||||
manifest: {
|
||||
appVersion: '2.1.0',
|
||||
formatVersion: 2 as const,
|
||||
sections: {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
jest.mocked(restoreData).mockResolvedValueOnce(restoreResult);
|
||||
jest.mocked(NativeFile.exists).mockResolvedValue(true);
|
||||
jest.mocked(NativeFile.copyFile).mockResolvedValue(undefined);
|
||||
jest.mocked(NativeZipArchive.unzip).mockResolvedValue(undefined);
|
||||
jest.mocked(finalizeRestoredPlugins).mockResolvedValueOnce([]);
|
||||
|
||||
await restoreBackup({ sourceUri: 'content://backup.zip' });
|
||||
|
||||
expect(NativeZipArchive.unzip).toHaveBeenCalledWith(
|
||||
'/cache/BackupData/plugins.zip',
|
||||
'/storage/Plugins',
|
||||
);
|
||||
expect(finalizeRestoredPlugins).toHaveBeenCalledWith(restoreResult);
|
||||
expect(
|
||||
jest.mocked(finalizeRestoredPlugins).mock.invocationCallOrder[0],
|
||||
).toBeGreaterThan(
|
||||
jest.mocked(NativeZipArchive.unzip).mock.invocationCallOrder[1],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
areAllBackupOptionsSelected,
|
||||
DEFAULT_BACKUP_OPTIONS,
|
||||
hasSelectedBackupOption,
|
||||
resolveBackupOptions,
|
||||
} from '../options';
|
||||
import { getSelectedBackupFileSections } from '../fileSections';
|
||||
import { ZipBackupName } from '../types';
|
||||
|
||||
jest.mock('@utils/Storages', () => ({
|
||||
NOVEL_STORAGE: '/storage/Novels',
|
||||
PLUGIN_STORAGE: '/storage/Plugins',
|
||||
}));
|
||||
|
||||
describe('backup options', () => {
|
||||
it('preserves the existing full-backup behavior by default', () => {
|
||||
expect(resolveBackupOptions()).toEqual(DEFAULT_BACKUP_OPTIONS);
|
||||
expect(areAllBackupOptionsSelected(resolveBackupOptions())).toBe(true);
|
||||
});
|
||||
|
||||
it('prevents downloaded files from being selected without library data', () => {
|
||||
expect(
|
||||
resolveBackupOptions({
|
||||
library: false,
|
||||
settings: true,
|
||||
plugins: false,
|
||||
downloadedFiles: true,
|
||||
}),
|
||||
).toEqual({
|
||||
library: false,
|
||||
settings: true,
|
||||
plugins: false,
|
||||
downloadedFiles: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('requires at least one selected section', () => {
|
||||
expect(
|
||||
hasSelectedBackupOption({
|
||||
library: false,
|
||||
settings: false,
|
||||
plugins: false,
|
||||
downloadedFiles: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('maps selected file sections to independent archives', () => {
|
||||
expect(
|
||||
getSelectedBackupFileSections({
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: false,
|
||||
}),
|
||||
).toEqual([
|
||||
{
|
||||
archiveName: ZipBackupName.PLUGINS,
|
||||
storagePath: '/storage/Plugins',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { reloadInstalledPlugins } from '@plugins/pluginManager';
|
||||
import {
|
||||
finalizeRestoredPlugins,
|
||||
getMissingRestorePluginIds,
|
||||
getRestoreCompletionText,
|
||||
type RestoreResult,
|
||||
} from '../restoreResult';
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
getString: (key: string, options?: Record<string, string | number>) => {
|
||||
const strings: Record<string, string> = {
|
||||
'backupScreen.settingsRestoreFailedSummary': 'settings failed',
|
||||
'backupScreen.missingPluginsAfterRestore': 'Missing plugins: %{plugins}',
|
||||
};
|
||||
const pluralStrings: Record<string, [string, string]> = {
|
||||
'backupScreen.backupRestoredSummary': [
|
||||
'Restored %{count} novel',
|
||||
'Restored %{count} novels',
|
||||
],
|
||||
'backupScreen.backupRestoredWithWarnings': [
|
||||
'Restored %{count} novel with warnings: %{warnings}',
|
||||
'Restored %{count} novels with warnings: %{warnings}',
|
||||
],
|
||||
'backupScreen.novelsRestoreFailedSummary': [
|
||||
'%{count} novel failed',
|
||||
'%{count} novels failed',
|
||||
],
|
||||
'backupScreen.categoriesRestoreFailedSummary': [
|
||||
'%{count} category failed',
|
||||
'%{count} categories failed',
|
||||
],
|
||||
'backupScreen.sectionsRestoreFailedSummary': [
|
||||
'%{count} backup section failed',
|
||||
'%{count} backup sections failed',
|
||||
],
|
||||
};
|
||||
const pluralString = pluralStrings[key];
|
||||
const template = pluralString
|
||||
? pluralString[options?.count === 1 ? 0 : 1]
|
||||
: strings[key] ?? key;
|
||||
|
||||
return Object.entries(options ?? {}).reduce(
|
||||
(text, [name, value]) => text.replace(`%{${name}}`, String(value)),
|
||||
template,
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@plugins/pluginManager', () => ({
|
||||
LOCAL_PLUGIN_ID: 'local',
|
||||
reloadInstalledPlugins: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/Storages', () => ({
|
||||
PLUGIN_STORAGE: '/storage/Plugins',
|
||||
}));
|
||||
|
||||
const successfulResult: RestoreResult = {
|
||||
novelCount: 4,
|
||||
failedNovelCount: 0,
|
||||
categoryCount: 2,
|
||||
failedCategoryCount: 0,
|
||||
settingsRestored: true,
|
||||
failedSectionCount: 0,
|
||||
pluginIds: ['installed'],
|
||||
manifest: {
|
||||
appVersion: '2.1.0',
|
||||
formatVersion: 2,
|
||||
sections: {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('restore result notifications', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(reloadInstalledPlugins).mockReset();
|
||||
});
|
||||
|
||||
it('uses a concise success message when the restore has no warnings', () => {
|
||||
expect(getRestoreCompletionText(successfulResult, [])).toBe(
|
||||
'Restored 4 novels',
|
||||
);
|
||||
});
|
||||
|
||||
it('aggregates restore failures and missing plugin identifiers', () => {
|
||||
expect(
|
||||
getRestoreCompletionText(
|
||||
{
|
||||
...successfulResult,
|
||||
failedNovelCount: 2,
|
||||
failedCategoryCount: 1,
|
||||
settingsRestored: false,
|
||||
failedSectionCount: 1,
|
||||
},
|
||||
['source.one', 'source.two'],
|
||||
),
|
||||
).toBe(
|
||||
'Restored 4 novels with warnings: 2 novels failed; 1 category failed; settings failed; 1 backup section failed; Missing plugins: source.one, source.two',
|
||||
);
|
||||
});
|
||||
|
||||
it('checks each referenced plugin once and ignores local novels', async () => {
|
||||
jest
|
||||
.mocked(NativeFile.exists)
|
||||
.mockImplementation(async path => path.includes('installed'));
|
||||
|
||||
await expect(
|
||||
getMissingRestorePluginIds(['local', 'installed', 'missing', 'missing']),
|
||||
).resolves.toEqual(['missing']);
|
||||
expect(NativeFile.exists).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('reloads restored plugin bundles and reports bundles that fail to load', async () => {
|
||||
jest.mocked(reloadInstalledPlugins).mockResolvedValueOnce(['invalid']);
|
||||
jest
|
||||
.mocked(NativeFile.exists)
|
||||
.mockImplementation(async path => path.includes('installed'));
|
||||
|
||||
await expect(
|
||||
finalizeRestoredPlugins({
|
||||
...successfulResult,
|
||||
pluginIds: ['installed', 'missing'],
|
||||
}),
|
||||
).resolves.toEqual(['missing', 'invalid']);
|
||||
});
|
||||
|
||||
it('does not reload plugins when that section was omitted', async () => {
|
||||
await finalizeRestoredPlugins({
|
||||
...successfulResult,
|
||||
pluginIds: [],
|
||||
manifest: {
|
||||
...successfulResult.manifest,
|
||||
sections: {
|
||||
...successfulResult.manifest.sections,
|
||||
plugins: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(reloadInstalledPlugins).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not describe an intentionally omitted library as zero novels', () => {
|
||||
expect(
|
||||
getRestoreCompletionText(
|
||||
{
|
||||
...successfulResult,
|
||||
novelCount: 0,
|
||||
manifest: {
|
||||
...successfulResult.manifest,
|
||||
sections: {
|
||||
...successfulResult.manifest.sections,
|
||||
library: false,
|
||||
downloadedFiles: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
[],
|
||||
),
|
||||
).toBe('backupScreen.backupRestored');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,215 @@
|
||||
import {
|
||||
_restoreNovelAndChapters,
|
||||
getAllNovels,
|
||||
} from '@database/queries/NovelQueries';
|
||||
import { getNovelChapters } from '@database/queries/ChapterQueries';
|
||||
import {
|
||||
_restoreCategory,
|
||||
getAllNovelCategories,
|
||||
getCategoriesFromDb,
|
||||
} from '@database/queries/CategoryQueries';
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { MMKVStorage } from '@utils/mmkv/mmkv';
|
||||
import { prepareBackupData, restoreData } from '../utils';
|
||||
import type { BackupOptions } from '../options';
|
||||
|
||||
jest.mock('@database/queries/NovelQueries', () => ({
|
||||
_restoreNovelAndChapters: jest.fn(),
|
||||
getAllNovels: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@database/queries/ChapterQueries', () => ({
|
||||
getNovelChapters: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@database/queries/CategoryQueries', () => ({
|
||||
_restoreCategory: jest.fn(),
|
||||
getAllNovelCategories: jest.fn(),
|
||||
getCategoriesFromDb: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@hooks/persisted/useSelfHost', () => ({
|
||||
SELF_HOST_BACKUP: 'SELF_HOST_BACKUP',
|
||||
}));
|
||||
|
||||
jest.mock('@hooks/persisted/migrations/trackerMigration', () => ({
|
||||
OLD_TRACKED_NOVEL_PREFIX: 'OLD_TRACKED_NOVEL_PREFIX',
|
||||
}));
|
||||
|
||||
jest.mock('@hooks/persisted/useUpdates', () => ({
|
||||
LAST_UPDATE_TIME: 'LAST_UPDATE_TIME',
|
||||
}));
|
||||
|
||||
jest.mock('@utils/mmkv/mmkv', () => ({
|
||||
MMKVStorage: {
|
||||
getAllKeys: jest.fn(() => []),
|
||||
getBoolean: jest.fn(),
|
||||
getString: jest.fn(),
|
||||
set: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@i18n/translations', () => ({
|
||||
getString: (key: string) => key,
|
||||
}));
|
||||
|
||||
jest.mock('@plugins/pluginManager', () => ({
|
||||
INSTALLED_PLUGINS_KEY: 'INSTALL_PLUGINS',
|
||||
}));
|
||||
|
||||
jest.mock('@utils/Storages', () => ({
|
||||
ROOT_STORAGE: '/storage',
|
||||
}));
|
||||
|
||||
const pluginOnlyOptions: BackupOptions = {
|
||||
library: false,
|
||||
settings: false,
|
||||
plugins: true,
|
||||
downloadedFiles: false,
|
||||
};
|
||||
|
||||
describe('selective backup data', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(NativeFile.exists).mockResolvedValue(false);
|
||||
jest.mocked(NativeFile.mkdir).mockResolvedValue(undefined);
|
||||
jest.mocked(NativeFile.writeFile).mockResolvedValue(undefined);
|
||||
jest.mocked(getAllNovels).mockResolvedValue([]);
|
||||
jest.mocked(getNovelChapters).mockResolvedValue([]);
|
||||
jest.mocked(getCategoriesFromDb).mockResolvedValue([]);
|
||||
jest.mocked(getAllNovelCategories).mockResolvedValue([]);
|
||||
});
|
||||
|
||||
it('writes the selected sections to the v2 manifest', async () => {
|
||||
await prepareBackupData('/cache', pluginOnlyOptions);
|
||||
|
||||
expect(NativeFile.writeFile).toHaveBeenCalledTimes(2);
|
||||
expect(NativeFile.writeFile).toHaveBeenCalledWith(
|
||||
'/cache/Version.json',
|
||||
expect.stringContaining(
|
||||
'"sections":{"library":false,"settings":false,"plugins":true,"downloadedFiles":false}',
|
||||
),
|
||||
);
|
||||
expect(getAllNovels).not.toHaveBeenCalled();
|
||||
expect(getCategoriesFromDb).not.toHaveBeenCalled();
|
||||
expect(NativeFile.writeFile).toHaveBeenCalledWith(
|
||||
'/cache/Plugins.json',
|
||||
'[]',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not warn about sections intentionally omitted by the manifest', async () => {
|
||||
jest
|
||||
.mocked(NativeFile.readFile)
|
||||
.mockResolvedValueOnce(
|
||||
JSON.stringify({
|
||||
appVersion: '2.1.0',
|
||||
formatVersion: 2,
|
||||
sections: pluginOnlyOptions,
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce('[]');
|
||||
jest
|
||||
.mocked(NativeFile.exists)
|
||||
.mockImplementation(async path => path.endsWith('/Plugins.json'));
|
||||
|
||||
const result = await restoreData('/cache');
|
||||
|
||||
expect(result).toMatchObject({
|
||||
failedNovelCount: 0,
|
||||
failedCategoryCount: 0,
|
||||
failedSectionCount: 0,
|
||||
settingsRestored: true,
|
||||
manifest: {
|
||||
formatVersion: 2,
|
||||
sections: pluginOnlyOptions,
|
||||
},
|
||||
});
|
||||
expect(_restoreNovelAndChapters).not.toHaveBeenCalled();
|
||||
expect(_restoreCategory).not.toHaveBeenCalled();
|
||||
expect(MMKVStorage.set).toHaveBeenCalledWith('INSTALL_PLUGINS', '[]');
|
||||
});
|
||||
|
||||
it('clears file-backed metadata when downloaded files are omitted', async () => {
|
||||
jest.mocked(getAllNovels).mockResolvedValueOnce([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Example',
|
||||
path: '/example',
|
||||
pluginId: 'source',
|
||||
cover: 'file:///storage/Novels/source/1/cover.png',
|
||||
},
|
||||
]);
|
||||
jest.mocked(getNovelChapters).mockResolvedValueOnce([
|
||||
{
|
||||
id: 10,
|
||||
novelId: 1,
|
||||
path: '/chapter-1',
|
||||
name: 'Chapter 1',
|
||||
isDownloaded: true,
|
||||
},
|
||||
] as Awaited<ReturnType<typeof getNovelChapters>>);
|
||||
|
||||
await prepareBackupData('/cache', {
|
||||
library: true,
|
||||
settings: false,
|
||||
plugins: false,
|
||||
downloadedFiles: false,
|
||||
});
|
||||
|
||||
const novelWrite = jest
|
||||
.mocked(NativeFile.writeFile)
|
||||
.mock.calls.find(([path]) => path.endsWith('/1.json'));
|
||||
expect(JSON.parse(novelWrite?.[1] ?? '{}')).toMatchObject({
|
||||
cover: null,
|
||||
chapters: [{ id: 10, isDownloaded: false }],
|
||||
});
|
||||
});
|
||||
|
||||
it('omits the installed-plugin registry when plugin files are excluded', async () => {
|
||||
jest
|
||||
.mocked(MMKVStorage.getAllKeys)
|
||||
.mockReturnValueOnce(['INSTALL_PLUGINS', 'OTHER_SETTING']);
|
||||
jest
|
||||
.mocked(MMKVStorage.getString)
|
||||
.mockImplementation(key =>
|
||||
key === 'INSTALL_PLUGINS'
|
||||
? '[{"id":"source"}]'
|
||||
: key === 'OTHER_SETTING'
|
||||
? 'kept'
|
||||
: undefined,
|
||||
);
|
||||
|
||||
await prepareBackupData('/cache', {
|
||||
library: false,
|
||||
settings: true,
|
||||
plugins: false,
|
||||
downloadedFiles: false,
|
||||
});
|
||||
|
||||
const settingsWrite = jest
|
||||
.mocked(NativeFile.writeFile)
|
||||
.mock.calls.find(([path]) => path.endsWith('/Setting.json'));
|
||||
expect(JSON.parse(settingsWrite?.[1] ?? '{}')).toEqual({
|
||||
OTHER_SETTING: 'kept',
|
||||
});
|
||||
});
|
||||
|
||||
it('treats backups without a section manifest as legacy full backups', async () => {
|
||||
jest
|
||||
.mocked(NativeFile.readFile)
|
||||
.mockResolvedValueOnce(JSON.stringify({ version: '2.0.0' }));
|
||||
|
||||
const result = await restoreData('/cache');
|
||||
|
||||
expect(result.manifest).toMatchObject({
|
||||
appVersion: '2.0.0',
|
||||
formatVersion: 1,
|
||||
sections: {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { getString } from '@i18n/translations';
|
||||
|
||||
export type BackupResult = {
|
||||
failedNovelCount: number;
|
||||
failedSectionCount: number;
|
||||
};
|
||||
|
||||
export const getBackupCompletionText = (result: BackupResult) => {
|
||||
const warnings: string[] = [];
|
||||
|
||||
if (result.failedNovelCount > 0) {
|
||||
warnings.push(
|
||||
getString('backupScreen.novelsBackupFailedSummary', {
|
||||
count: result.failedNovelCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (result.failedSectionCount > 0) {
|
||||
warnings.push(
|
||||
getString('backupScreen.sectionsBackupFailedSummary', {
|
||||
count: result.failedSectionCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (warnings.length === 0) {
|
||||
return getString('backupScreen.backupCreated');
|
||||
}
|
||||
|
||||
return getString('backupScreen.backupCreatedWithWarnings', {
|
||||
warnings: warnings.join('; '),
|
||||
});
|
||||
};
|
||||
@@ -2,16 +2,51 @@ import { DriveFile } from '@api/drive/types';
|
||||
import { sleep } from '@utils/sleep';
|
||||
import { exists } from '@api/drive';
|
||||
import { getString } from '@i18n/translations';
|
||||
import { CACHE_DIR_PATH, prepareBackupData, restoreData } from '../utils';
|
||||
import {
|
||||
CACHE_DIR_PATH,
|
||||
clearBackupCache,
|
||||
prepareBackupData,
|
||||
restoreData,
|
||||
} from '../utils';
|
||||
import {
|
||||
finalizeRestoredPlugins,
|
||||
getRestoreCompletionText,
|
||||
} from '../restoreResult';
|
||||
import { getBackupCompletionText } from '../backupResult';
|
||||
import { download, updateMetadata, uploadMedia } from '@api/drive/request';
|
||||
import { ZipBackupName } from '../types';
|
||||
import { ROOT_STORAGE } from '@utils/Storages';
|
||||
import type { TaskProgressUpdater } from '@services/backgroundTasks/contracts';
|
||||
import type {
|
||||
DriveBackupData,
|
||||
TaskProgressUpdater,
|
||||
} from '@services/backgroundTasks/contracts';
|
||||
import { getSelectedBackupFileSections } from '../fileSections';
|
||||
import { resolveBackupOptions } from '../options';
|
||||
|
||||
const uploadBackupSection = async (
|
||||
sourcePath: string,
|
||||
name: ZipBackupName,
|
||||
backupFolder: DriveFile,
|
||||
) => {
|
||||
const file = await uploadMedia(sourcePath);
|
||||
await updateMetadata(
|
||||
file.id,
|
||||
{
|
||||
name,
|
||||
mimeType: 'application/zip',
|
||||
parents: [backupFolder.id],
|
||||
},
|
||||
file.parents[0],
|
||||
);
|
||||
};
|
||||
|
||||
export const createDriveBackup = async (
|
||||
backupFolder: DriveFile,
|
||||
data: DriveBackupData,
|
||||
setMeta: TaskProgressUpdater,
|
||||
) => {
|
||||
const backupFolder = 'backupFolder' in data ? data.backupFolder : data;
|
||||
const requestedOptions = 'backupFolder' in data ? data.options : undefined;
|
||||
const options = resolveBackupOptions(requestedOptions);
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
isRunning: true,
|
||||
@@ -19,7 +54,7 @@ export const createDriveBackup = async (
|
||||
progressText: getString('backupScreen.preparingData'),
|
||||
}));
|
||||
|
||||
await prepareBackupData(CACHE_DIR_PATH);
|
||||
const backupResult = await prepareBackupData(CACHE_DIR_PATH, options);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
@@ -29,39 +64,29 @@ export const createDriveBackup = async (
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const file = await uploadMedia(CACHE_DIR_PATH);
|
||||
|
||||
await updateMetadata(
|
||||
file.id,
|
||||
{
|
||||
name: ZipBackupName.DATA,
|
||||
mimeType: 'application/zip',
|
||||
parents: [backupFolder.id],
|
||||
},
|
||||
file.parents[0],
|
||||
);
|
||||
await uploadBackupSection(CACHE_DIR_PATH, ZipBackupName.DATA, backupFolder);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 2 / 3,
|
||||
progressText: getString('backupScreen.uploadingDownloadedFiles'),
|
||||
progressText: getString('backupScreen.uploadingSelectedFiles'),
|
||||
}));
|
||||
|
||||
const file2 = await uploadMedia(ROOT_STORAGE);
|
||||
await updateMetadata(
|
||||
file2.id,
|
||||
{
|
||||
name: ZipBackupName.DOWNLOAD,
|
||||
mimeType: 'application/zip',
|
||||
parents: [backupFolder.id],
|
||||
},
|
||||
file2.parents[0],
|
||||
);
|
||||
for (const section of getSelectedBackupFileSections(options)) {
|
||||
await uploadBackupSection(
|
||||
section.storagePath,
|
||||
section.archiveName,
|
||||
backupFolder,
|
||||
);
|
||||
}
|
||||
|
||||
const completionText = getBackupCompletionText(backupResult);
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 3 / 3,
|
||||
isRunning: false,
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -77,15 +102,11 @@ export const driveRestore = async (
|
||||
}));
|
||||
|
||||
const zipDataFile = await exists(ZipBackupName.DATA, false, backupFolder.id);
|
||||
const zipDownloadFile = await exists(
|
||||
ZipBackupName.DOWNLOAD,
|
||||
false,
|
||||
backupFolder.id,
|
||||
);
|
||||
if (!zipDataFile || !zipDownloadFile) {
|
||||
if (!zipDataFile) {
|
||||
throw new Error(getString('backupScreen.invalidBackupFolder'));
|
||||
}
|
||||
|
||||
await clearBackupCache();
|
||||
await download(zipDataFile, CACHE_DIR_PATH);
|
||||
await sleep(500);
|
||||
|
||||
@@ -95,20 +116,47 @@ export const driveRestore = async (
|
||||
progressText: getString('backupScreen.restoringData'),
|
||||
}));
|
||||
|
||||
await restoreData(CACHE_DIR_PATH);
|
||||
const restoreResult = await restoreData(CACHE_DIR_PATH, setMeta);
|
||||
await sleep(500);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 2 / 3,
|
||||
progressText: getString('backupScreen.downloadingDownloadedFiles'),
|
||||
progressText: getString('backupScreen.restoringSelectedFiles'),
|
||||
}));
|
||||
|
||||
await download(zipDownloadFile, ROOT_STORAGE);
|
||||
if (restoreResult.manifest.formatVersion === 1) {
|
||||
const legacyFile = await exists(
|
||||
ZipBackupName.DOWNLOAD,
|
||||
false,
|
||||
backupFolder.id,
|
||||
);
|
||||
if (!legacyFile) {
|
||||
throw new Error(getString('backupScreen.invalidBackupFolder'));
|
||||
}
|
||||
await download(legacyFile, ROOT_STORAGE);
|
||||
} else {
|
||||
for (const section of getSelectedBackupFileSections(
|
||||
restoreResult.manifest.sections,
|
||||
)) {
|
||||
const file = await exists(section.archiveName, false, backupFolder.id);
|
||||
if (!file) {
|
||||
throw new Error(getString('backupScreen.invalidBackupFolder'));
|
||||
}
|
||||
await download(file, section.storagePath);
|
||||
}
|
||||
}
|
||||
const missingPluginIds = await finalizeRestoredPlugins(restoreResult);
|
||||
const completionText = getRestoreCompletionText(
|
||||
restoreResult,
|
||||
missingPluginIds,
|
||||
);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 3 / 3,
|
||||
isRunning: false,
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { NOVEL_STORAGE, PLUGIN_STORAGE } from '@utils/Storages';
|
||||
import type { BackupOptions } from './options';
|
||||
import { ZipBackupName } from './types';
|
||||
|
||||
export type BackupFileSection = {
|
||||
archiveName: ZipBackupName;
|
||||
storagePath: string;
|
||||
};
|
||||
|
||||
export const getSelectedBackupFileSections = (
|
||||
options: BackupOptions,
|
||||
): BackupFileSection[] => {
|
||||
const sections: BackupFileSection[] = [];
|
||||
|
||||
if (options.plugins) {
|
||||
sections.push({
|
||||
archiveName: ZipBackupName.PLUGINS,
|
||||
storagePath: PLUGIN_STORAGE,
|
||||
});
|
||||
}
|
||||
if (options.downloadedFiles) {
|
||||
sections.push({
|
||||
archiveName: ZipBackupName.NOVEL_FILES,
|
||||
storagePath: NOVEL_STORAGE,
|
||||
});
|
||||
}
|
||||
|
||||
return sections;
|
||||
};
|
||||
@@ -1,18 +1,33 @@
|
||||
import { showToast } from '@utils/showToast';
|
||||
import { CACHE_DIR_PATH, prepareBackupData, restoreData } from '../utils';
|
||||
import NativeZipArchive from '@modules/native-zip-archive'
|
||||
import {
|
||||
CACHE_DIR_PATH,
|
||||
clearBackupCache,
|
||||
prepareBackupData,
|
||||
restoreData,
|
||||
} from '../utils';
|
||||
import {
|
||||
finalizeRestoredPlugins,
|
||||
getRestoreCompletionText,
|
||||
} from '../restoreResult';
|
||||
import { getBackupCompletionText } from '../backupResult';
|
||||
import NativeZipArchive from '@modules/native-zip-archive';
|
||||
import { ROOT_STORAGE } from '@utils/Storages';
|
||||
import { ZipBackupName } from '../types';
|
||||
import NativeFile from '@modules/native-file'
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { getString } from '@i18n/translations';
|
||||
import type { TaskProgressUpdater } from '@services/backgroundTasks/contracts';
|
||||
import { sleep } from '@utils/sleep';
|
||||
import { getSelectedBackupFileSections } from '../fileSections';
|
||||
import { resolveBackupOptions, type BackupOptions } from '../options';
|
||||
|
||||
export const createBackup = async (
|
||||
{ destinationUri }: { destinationUri: string },
|
||||
{
|
||||
destinationUri,
|
||||
options: requestedOptions,
|
||||
}: { destinationUri: string; options?: BackupOptions },
|
||||
setMeta?: TaskProgressUpdater,
|
||||
) => {
|
||||
try {
|
||||
const options = resolveBackupOptions(requestedOptions);
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
isRunning: true,
|
||||
@@ -20,20 +35,22 @@ export const createBackup = async (
|
||||
progressText: getString('backupScreen.preparingData'),
|
||||
}));
|
||||
|
||||
await prepareBackupData(CACHE_DIR_PATH);
|
||||
const backupResult = await prepareBackupData(CACHE_DIR_PATH, options);
|
||||
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
progress: 1 / 4,
|
||||
progressText: getString('backupScreen.uploadingDownloadedFiles'),
|
||||
progressText: getString('backupScreen.preparingSelectedFiles'),
|
||||
}));
|
||||
|
||||
await sleep(200);
|
||||
|
||||
await NativeZipArchive.zip(
|
||||
ROOT_STORAGE,
|
||||
CACHE_DIR_PATH + '/' + ZipBackupName.DOWNLOAD,
|
||||
);
|
||||
for (const section of getSelectedBackupFileSections(options)) {
|
||||
await NativeZipArchive.zip(
|
||||
section.storagePath,
|
||||
`${CACHE_DIR_PATH}/${section.archiveName}`,
|
||||
);
|
||||
}
|
||||
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
@@ -53,19 +70,19 @@ export const createBackup = async (
|
||||
|
||||
await NativeFile.copyFile(CACHE_DIR_PATH + '.zip', destinationUri);
|
||||
|
||||
const completionText = getBackupCompletionText(backupResult);
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
progress: 4 / 4,
|
||||
isRunning: false,
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
|
||||
showToast(getString('backupScreen.backupCreated'));
|
||||
} catch (error: any) {
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
isRunning: false,
|
||||
}));
|
||||
showToast(error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -82,9 +99,7 @@ export const restoreBackup = async (
|
||||
progressText: getString('backupScreen.downloadingData'),
|
||||
}));
|
||||
|
||||
if (await NativeFile.exists(CACHE_DIR_PATH)) {
|
||||
await NativeFile.unlink(CACHE_DIR_PATH);
|
||||
}
|
||||
await clearBackupCache();
|
||||
const localPath = CACHE_DIR_PATH + '-source.zip';
|
||||
await NativeFile.copyFile(sourceUri, localPath);
|
||||
|
||||
@@ -106,35 +121,51 @@ export const restoreBackup = async (
|
||||
|
||||
await sleep(200);
|
||||
|
||||
await restoreData(CACHE_DIR_PATH);
|
||||
const restoreResult = await restoreData(CACHE_DIR_PATH, setMeta);
|
||||
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
progress: 3 / 4,
|
||||
progressText: getString('backupScreen.downloadingDownloadedFiles'),
|
||||
progressText: getString('backupScreen.restoringSelectedFiles'),
|
||||
}));
|
||||
|
||||
await sleep(200);
|
||||
|
||||
// TODO: unlink here too?
|
||||
await NativeZipArchive.unzip(
|
||||
CACHE_DIR_PATH + '/' + ZipBackupName.DOWNLOAD,
|
||||
ROOT_STORAGE,
|
||||
if (restoreResult.manifest.formatVersion === 1) {
|
||||
const legacyArchive = CACHE_DIR_PATH + '/' + ZipBackupName.DOWNLOAD;
|
||||
if (!(await NativeFile.exists(legacyArchive))) {
|
||||
throw new Error(getString('backupScreen.invalidBackupFolder'));
|
||||
}
|
||||
await NativeZipArchive.unzip(legacyArchive, ROOT_STORAGE);
|
||||
} else {
|
||||
for (const section of getSelectedBackupFileSections(
|
||||
restoreResult.manifest.sections,
|
||||
)) {
|
||||
const archivePath = `${CACHE_DIR_PATH}/${section.archiveName}`;
|
||||
if (!(await NativeFile.exists(archivePath))) {
|
||||
throw new Error(getString('backupScreen.invalidBackupFolder'));
|
||||
}
|
||||
await NativeZipArchive.unzip(archivePath, section.storagePath);
|
||||
}
|
||||
}
|
||||
const missingPluginIds = await finalizeRestoredPlugins(restoreResult);
|
||||
const completionText = getRestoreCompletionText(
|
||||
restoreResult,
|
||||
missingPluginIds,
|
||||
);
|
||||
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
progress: 4 / 4,
|
||||
isRunning: false,
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
|
||||
showToast(getString('backupScreen.backupRestored'));
|
||||
} catch (error: any) {
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
isRunning: false,
|
||||
}));
|
||||
showToast(error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
export type BackupOptions = {
|
||||
library: boolean;
|
||||
settings: boolean;
|
||||
plugins: boolean;
|
||||
downloadedFiles: boolean;
|
||||
};
|
||||
|
||||
export const DEFAULT_BACKUP_OPTIONS: BackupOptions = {
|
||||
library: true,
|
||||
settings: true,
|
||||
plugins: true,
|
||||
downloadedFiles: true,
|
||||
};
|
||||
|
||||
export const resolveBackupOptions = (
|
||||
options?: BackupOptions,
|
||||
): BackupOptions => {
|
||||
const resolved = {
|
||||
...DEFAULT_BACKUP_OPTIONS,
|
||||
...options,
|
||||
};
|
||||
|
||||
return {
|
||||
...resolved,
|
||||
downloadedFiles: resolved.library && resolved.downloadedFiles,
|
||||
};
|
||||
};
|
||||
|
||||
export const hasSelectedBackupOption = (options: BackupOptions) =>
|
||||
Object.values(options).some(Boolean);
|
||||
|
||||
export const areAllBackupOptionsSelected = (options: BackupOptions) =>
|
||||
Object.values(options).every(Boolean);
|
||||
@@ -0,0 +1,107 @@
|
||||
import { getString } from '@i18n/translations';
|
||||
import NativeFile from '@modules/native-file';
|
||||
import {
|
||||
LOCAL_PLUGIN_ID,
|
||||
reloadInstalledPlugins,
|
||||
} from '@plugins/pluginManager';
|
||||
import { PLUGIN_STORAGE } from '@utils/Storages';
|
||||
import type { ResolvedBackupManifest } from './types';
|
||||
|
||||
export type RestoreResult = {
|
||||
novelCount: number;
|
||||
failedNovelCount: number;
|
||||
categoryCount: number;
|
||||
failedCategoryCount: number;
|
||||
settingsRestored: boolean;
|
||||
failedSectionCount: number;
|
||||
pluginIds: string[];
|
||||
manifest: ResolvedBackupManifest;
|
||||
};
|
||||
|
||||
export const getMissingRestorePluginIds = async (pluginIds: string[]) => {
|
||||
const uniquePluginIds = [...new Set(pluginIds)].filter(
|
||||
pluginId => pluginId !== LOCAL_PLUGIN_ID,
|
||||
);
|
||||
const pluginAvailability = await Promise.all(
|
||||
uniquePluginIds.map(async pluginId => ({
|
||||
pluginId,
|
||||
exists: await NativeFile.exists(`${PLUGIN_STORAGE}/${pluginId}/index.js`),
|
||||
})),
|
||||
);
|
||||
|
||||
return pluginAvailability
|
||||
.filter(plugin => !plugin.exists)
|
||||
.map(plugin => plugin.pluginId);
|
||||
};
|
||||
|
||||
export const finalizeRestoredPlugins = async (result: RestoreResult) => {
|
||||
const failedPluginIds = result.manifest.sections.plugins
|
||||
? await reloadInstalledPlugins()
|
||||
: [];
|
||||
|
||||
return [
|
||||
...new Set([
|
||||
...(await getMissingRestorePluginIds(result.pluginIds)),
|
||||
...failedPluginIds,
|
||||
]),
|
||||
];
|
||||
};
|
||||
|
||||
export const getRestoreCompletionText = (
|
||||
result: RestoreResult,
|
||||
missingPluginIds: string[],
|
||||
) => {
|
||||
const warnings: string[] = [];
|
||||
|
||||
if (result.failedNovelCount > 0) {
|
||||
warnings.push(
|
||||
getString('backupScreen.novelsRestoreFailedSummary', {
|
||||
count: result.failedNovelCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (result.failedCategoryCount > 0) {
|
||||
warnings.push(
|
||||
getString('backupScreen.categoriesRestoreFailedSummary', {
|
||||
count: result.failedCategoryCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (!result.settingsRestored) {
|
||||
warnings.push(getString('backupScreen.settingsRestoreFailedSummary'));
|
||||
}
|
||||
if (result.failedSectionCount > 0) {
|
||||
warnings.push(
|
||||
getString('backupScreen.sectionsRestoreFailedSummary', {
|
||||
count: result.failedSectionCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (missingPluginIds.length > 0) {
|
||||
warnings.push(
|
||||
getString('backupScreen.missingPluginsAfterRestore', {
|
||||
plugins: missingPluginIds.join(', '),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (warnings.length === 0) {
|
||||
if (!result.manifest.sections.library) {
|
||||
return getString('backupScreen.backupRestored');
|
||||
}
|
||||
return getString('backupScreen.backupRestoredSummary', {
|
||||
count: result.novelCount,
|
||||
});
|
||||
}
|
||||
|
||||
if (!result.manifest.sections.library) {
|
||||
return getString('backupScreen.backupRestoredSelectedWithWarnings', {
|
||||
warnings: warnings.join('; '),
|
||||
});
|
||||
}
|
||||
|
||||
return getString('backupScreen.backupRestoredWithWarnings', {
|
||||
count: result.novelCount,
|
||||
warnings: warnings.join('; '),
|
||||
});
|
||||
};
|
||||
@@ -1,18 +1,31 @@
|
||||
import { sleep } from '@utils/sleep';
|
||||
import { download, upload } from '@api/remote';
|
||||
import { getString } from '@i18n/translations';
|
||||
import { CACHE_DIR_PATH, prepareBackupData, restoreData } from '../utils';
|
||||
import {
|
||||
CACHE_DIR_PATH,
|
||||
clearBackupCache,
|
||||
prepareBackupData,
|
||||
restoreData,
|
||||
} from '../utils';
|
||||
import {
|
||||
finalizeRestoredPlugins,
|
||||
getRestoreCompletionText,
|
||||
} from '../restoreResult';
|
||||
import { getBackupCompletionText } from '../backupResult';
|
||||
import { ZipBackupName } from '../types';
|
||||
import { ROOT_STORAGE } from '@utils/Storages';
|
||||
import type {
|
||||
SelfHostData,
|
||||
TaskProgressUpdater,
|
||||
} from '@services/backgroundTasks/contracts';
|
||||
import { getSelectedBackupFileSections } from '../fileSections';
|
||||
import { resolveBackupOptions } from '../options';
|
||||
|
||||
export const createSelfHostBackup = async (
|
||||
{ host, backupFolder }: SelfHostData,
|
||||
{ host, backupFolder, options: requestedOptions }: SelfHostData,
|
||||
setMeta: TaskProgressUpdater,
|
||||
) => {
|
||||
const options = resolveBackupOptions(requestedOptions);
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
isRunning: true,
|
||||
@@ -20,7 +33,7 @@ export const createSelfHostBackup = async (
|
||||
progressText: getString('backupScreen.preparingData'),
|
||||
}));
|
||||
|
||||
await prepareBackupData(CACHE_DIR_PATH);
|
||||
const backupResult = await prepareBackupData(CACHE_DIR_PATH, options);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
@@ -35,17 +48,22 @@ export const createSelfHostBackup = async (
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 2 / 3,
|
||||
progressText: getString('backupScreen.uploadingDownloadedFiles'),
|
||||
progressText: getString('backupScreen.uploadingSelectedFiles'),
|
||||
}));
|
||||
|
||||
await sleep(200);
|
||||
|
||||
await upload(host, backupFolder, ZipBackupName.DOWNLOAD, ROOT_STORAGE);
|
||||
for (const section of getSelectedBackupFileSections(options)) {
|
||||
await upload(host, backupFolder, section.archiveName, section.storagePath);
|
||||
}
|
||||
|
||||
const completionText = getBackupCompletionText(backupResult);
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 3 / 3,
|
||||
isRunning: false,
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -60,6 +78,7 @@ export const selfHostRestore = async (
|
||||
progressText: getString('backupScreen.downloadingData'),
|
||||
}));
|
||||
|
||||
await clearBackupCache();
|
||||
await download(host, backupFolder, ZipBackupName.DATA, CACHE_DIR_PATH);
|
||||
|
||||
setMeta(meta => ({
|
||||
@@ -70,21 +89,41 @@ export const selfHostRestore = async (
|
||||
|
||||
await sleep(200);
|
||||
|
||||
await restoreData(CACHE_DIR_PATH);
|
||||
const restoreResult = await restoreData(CACHE_DIR_PATH, setMeta);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 2 / 3,
|
||||
progressText: getString('backupScreen.downloadingDownloadedFiles'),
|
||||
progressText: getString('backupScreen.restoringSelectedFiles'),
|
||||
}));
|
||||
|
||||
await sleep(200);
|
||||
|
||||
await download(host, backupFolder, ZipBackupName.DOWNLOAD, ROOT_STORAGE);
|
||||
if (restoreResult.manifest.formatVersion === 1) {
|
||||
await download(host, backupFolder, ZipBackupName.DOWNLOAD, ROOT_STORAGE);
|
||||
} else {
|
||||
for (const section of getSelectedBackupFileSections(
|
||||
restoreResult.manifest.sections,
|
||||
)) {
|
||||
await download(
|
||||
host,
|
||||
backupFolder,
|
||||
section.archiveName,
|
||||
section.storagePath,
|
||||
);
|
||||
}
|
||||
}
|
||||
const missingPluginIds = await finalizeRestoredPlugins(restoreResult);
|
||||
const completionText = getRestoreCompletionText(
|
||||
restoreResult,
|
||||
missingPluginIds,
|
||||
);
|
||||
|
||||
setMeta(meta => ({
|
||||
...meta,
|
||||
progress: 3 / 3,
|
||||
isRunning: false,
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
import type { BackupOptions } from './options';
|
||||
|
||||
export enum ZipBackupName {
|
||||
DATA = 'data.zip',
|
||||
DOWNLOAD = 'download.zip',
|
||||
NOVEL_FILES = 'novel-files.zip',
|
||||
PLUGINS = 'plugins.zip',
|
||||
}
|
||||
|
||||
export enum BackupEntryName {
|
||||
VERSION = 'Version.json',
|
||||
CATEGORY = 'Category.json',
|
||||
SETTING = 'Setting.json',
|
||||
PLUGIN_METADATA = 'Plugins.json',
|
||||
NOVEL_AND_CHAPTERS = 'NovelAndChapters',
|
||||
}
|
||||
|
||||
export type BackupManifest = {
|
||||
appVersion: string;
|
||||
formatVersion: 2;
|
||||
sections: BackupOptions;
|
||||
};
|
||||
|
||||
export type ResolvedBackupManifest =
|
||||
| BackupManifest
|
||||
| {
|
||||
appVersion?: string;
|
||||
formatVersion: 1;
|
||||
sections: BackupOptions;
|
||||
};
|
||||
|
||||
+252
-158
@@ -14,24 +14,43 @@ import {
|
||||
getCategoriesFromDb,
|
||||
} from '@database/queries/CategoryQueries';
|
||||
import { BackupCategory, BackupNovel } from '@database/types';
|
||||
import { BackupEntryName } from './types';
|
||||
import {
|
||||
BackupEntryName,
|
||||
type BackupManifest,
|
||||
type ResolvedBackupManifest,
|
||||
} from './types';
|
||||
import { ROOT_STORAGE } from '@utils/Storages';
|
||||
import { BACKGROUND_TASKS_STORE_KEY } from '@services/backgroundTasks/constants';
|
||||
import type { TaskProgressUpdater } from '@services/backgroundTasks/contracts';
|
||||
import NativeFile from '@modules/native-file';
|
||||
import { showToast } from '@utils/showToast';
|
||||
import { getString } from '@i18n/translations';
|
||||
import type { RestoreResult } from './restoreResult';
|
||||
import type { BackupResult } from './backupResult';
|
||||
import {
|
||||
DEFAULT_BACKUP_OPTIONS,
|
||||
resolveBackupOptions,
|
||||
type BackupOptions,
|
||||
} from './options';
|
||||
import { INSTALLED_PLUGINS_KEY } from '@plugins/pluginManager';
|
||||
|
||||
const APP_STORAGE_URI = 'file://' + ROOT_STORAGE;
|
||||
|
||||
export const CACHE_DIR_PATH =
|
||||
NativeFile.ExternalCachesDirectoryPath + '/BackupData';
|
||||
|
||||
const backupMMKVData = () => {
|
||||
export const clearBackupCache = async (cacheDirPath = CACHE_DIR_PATH) => {
|
||||
if (await NativeFile.exists(cacheDirPath)) {
|
||||
await NativeFile.unlink(cacheDirPath);
|
||||
}
|
||||
};
|
||||
|
||||
const backupMMKVData = (options: BackupOptions) => {
|
||||
const excludeKeys = [
|
||||
BACKGROUND_TASKS_STORE_KEY,
|
||||
OLD_TRACKED_NOVEL_PREFIX,
|
||||
SELF_HOST_BACKUP,
|
||||
LAST_UPDATE_TIME,
|
||||
...(options.plugins ? [] : [INSTALLED_PLUGINS_KEY]),
|
||||
];
|
||||
const keys = MMKVStorage.getAllKeys().filter(
|
||||
key => !excludeKeys.includes(key),
|
||||
@@ -56,221 +75,296 @@ const restoreMMKVData = (data: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const prepareBackupData = async (cacheDirPath: string) => {
|
||||
export const prepareBackupData = async (
|
||||
cacheDirPath: string,
|
||||
requestedOptions?: BackupOptions,
|
||||
): Promise<BackupResult> => {
|
||||
const options = resolveBackupOptions(requestedOptions);
|
||||
const novelDirPath = cacheDirPath + '/' + BackupEntryName.NOVEL_AND_CHAPTERS;
|
||||
if (await NativeFile.exists(novelDirPath)) {
|
||||
await NativeFile.unlink(novelDirPath);
|
||||
}
|
||||
let failedNovelCount = 0;
|
||||
let failedSectionCount = 0;
|
||||
|
||||
await NativeFile.mkdir(novelDirPath); // this also creates cacheDirPath
|
||||
await clearBackupCache(cacheDirPath);
|
||||
await NativeFile.mkdir(cacheDirPath);
|
||||
|
||||
// version
|
||||
try {
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.VERSION,
|
||||
JSON.stringify({ version: version }),
|
||||
);
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.versionFileWriteFailed', {
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
const manifest: BackupManifest = {
|
||||
appVersion: version,
|
||||
formatVersion: 2,
|
||||
sections: options,
|
||||
};
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.VERSION,
|
||||
JSON.stringify(manifest),
|
||||
);
|
||||
|
||||
// novels
|
||||
await getAllNovels().then(async novels => {
|
||||
for (const novel of novels) {
|
||||
try {
|
||||
const chapters = await getNovelChapters(novel.id);
|
||||
await NativeFile.writeFile(
|
||||
novelDirPath + '/' + novel.id + '.json',
|
||||
JSON.stringify({
|
||||
chapters: chapters,
|
||||
...novel,
|
||||
cover: novel.cover?.replace(APP_STORAGE_URI, ''),
|
||||
}),
|
||||
);
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.novelBackupFailed', {
|
||||
novelName: novel.name,
|
||||
error: error?.message,
|
||||
}),
|
||||
);
|
||||
if (options.library) {
|
||||
await NativeFile.mkdir(novelDirPath);
|
||||
await getAllNovels().then(async novels => {
|
||||
for (const novel of novels) {
|
||||
try {
|
||||
const chapters = await getNovelChapters(novel.id);
|
||||
const backedUpChapters = options.downloadedFiles
|
||||
? chapters
|
||||
: chapters.map(chapter => ({
|
||||
...chapter,
|
||||
isDownloaded: false,
|
||||
}));
|
||||
const isStoredCover = novel.cover?.startsWith(APP_STORAGE_URI);
|
||||
await NativeFile.writeFile(
|
||||
novelDirPath + '/' + novel.id + '.json',
|
||||
JSON.stringify({
|
||||
chapters: backedUpChapters,
|
||||
...novel,
|
||||
cover:
|
||||
!options.downloadedFiles && isStoredCover
|
||||
? null
|
||||
: novel.cover?.replace(APP_STORAGE_URI, ''),
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
failedNovelCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// categories
|
||||
try {
|
||||
const categories = await getCategoriesFromDb();
|
||||
const novelCategories = await getAllNovelCategories();
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.CATEGORY,
|
||||
JSON.stringify(
|
||||
categories.map(category => {
|
||||
return {
|
||||
...category,
|
||||
novelIds: novelCategories
|
||||
.filter(nc => nc.categoryId === category.id)
|
||||
.map(nc => nc.novelId),
|
||||
};
|
||||
}),
|
||||
),
|
||||
);
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.categoryFileWriteFailed', {
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
// categories
|
||||
try {
|
||||
const categories = await getCategoriesFromDb();
|
||||
const novelCategories = await getAllNovelCategories();
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.CATEGORY,
|
||||
JSON.stringify(
|
||||
categories.map(category => {
|
||||
return {
|
||||
...category,
|
||||
novelIds: novelCategories
|
||||
.filter(nc => nc.categoryId === category.id)
|
||||
.map(nc => nc.novelId),
|
||||
};
|
||||
}),
|
||||
),
|
||||
);
|
||||
} catch {
|
||||
failedSectionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// settings
|
||||
if (options.settings) {
|
||||
try {
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.SETTING,
|
||||
JSON.stringify(backupMMKVData(options)),
|
||||
);
|
||||
} catch {
|
||||
failedSectionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// installed plugin registry
|
||||
if (options.plugins) {
|
||||
try {
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.PLUGIN_METADATA,
|
||||
MMKVStorage.getString(INSTALLED_PLUGINS_KEY) ?? '[]',
|
||||
);
|
||||
} catch {
|
||||
failedSectionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
failedNovelCount,
|
||||
failedSectionCount,
|
||||
};
|
||||
};
|
||||
|
||||
const getBackupManifest = async (
|
||||
cacheDirPath: string,
|
||||
): Promise<ResolvedBackupManifest> => {
|
||||
try {
|
||||
await NativeFile.writeFile(
|
||||
cacheDirPath + '/' + BackupEntryName.SETTING,
|
||||
JSON.stringify(backupMMKVData()),
|
||||
);
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.settingsFileWriteFailed', {
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
const fileContent = await NativeFile.readFile(
|
||||
cacheDirPath + '/' + BackupEntryName.VERSION,
|
||||
);
|
||||
const data = JSON.parse(fileContent) as Partial<BackupManifest> & {
|
||||
version?: string;
|
||||
};
|
||||
if (data.formatVersion === 2 && data.sections) {
|
||||
return {
|
||||
appVersion: data.appVersion ?? data.version ?? '',
|
||||
formatVersion: 2,
|
||||
sections: resolveBackupOptions(data.sections),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
appVersion: data.version,
|
||||
formatVersion: 1,
|
||||
sections: DEFAULT_BACKUP_OPTIONS,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
formatVersion: 1,
|
||||
sections: DEFAULT_BACKUP_OPTIONS,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const restoreData = async (cacheDirPath: string) => {
|
||||
const updateRestoreProgress = (
|
||||
setMeta: TaskProgressUpdater | undefined,
|
||||
progressText: string,
|
||||
) => {
|
||||
setMeta?.(meta => ({
|
||||
...meta,
|
||||
progressText,
|
||||
}));
|
||||
};
|
||||
|
||||
export const restoreData = async (
|
||||
cacheDirPath: string,
|
||||
setMeta?: TaskProgressUpdater,
|
||||
): Promise<RestoreResult> => {
|
||||
const manifest = await getBackupManifest(cacheDirPath);
|
||||
const novelDirPath = cacheDirPath + '/' + BackupEntryName.NOVEL_AND_CHAPTERS;
|
||||
const pluginIds = new Set<string>();
|
||||
|
||||
// version
|
||||
// nothing to do
|
||||
|
||||
// novels
|
||||
showToast(getString('backupScreen.restoringNovels'));
|
||||
if (manifest.sections.library) {
|
||||
updateRestoreProgress(setMeta, getString('backupScreen.restoringNovels'));
|
||||
}
|
||||
let novelCount = 0;
|
||||
let failedCount = 0;
|
||||
let failedSectionCount = 0;
|
||||
|
||||
if (!(await NativeFile.exists(novelDirPath))) {
|
||||
showToast(getString('backupScreen.novelDirectoryNotFound'));
|
||||
if (!manifest.sections.library) {
|
||||
// Intentionally omitted from this backup.
|
||||
} else if (!(await NativeFile.exists(novelDirPath))) {
|
||||
failedSectionCount++;
|
||||
} else {
|
||||
try {
|
||||
const items = await NativeFile.readDir(novelDirPath);
|
||||
for (const item of items) {
|
||||
if (!item.isDirectory) {
|
||||
try {
|
||||
const fileContent = await NativeFile.readFile(item.path);
|
||||
const backupNovel = JSON.parse(fileContent) as BackupNovel;
|
||||
const items = (await NativeFile.readDir(novelDirPath)).filter(
|
||||
item => !item.isDirectory,
|
||||
);
|
||||
for (const [index, item] of items.entries()) {
|
||||
updateRestoreProgress(
|
||||
setMeta,
|
||||
getString('backupScreen.restoringNovelsProgress', {
|
||||
current: index + 1,
|
||||
total: items.length,
|
||||
}),
|
||||
);
|
||||
try {
|
||||
const fileContent = await NativeFile.readFile(item.path);
|
||||
const backupNovel = JSON.parse(fileContent) as BackupNovel;
|
||||
pluginIds.add(backupNovel.pluginId);
|
||||
|
||||
if (!backupNovel.cover?.startsWith('http')) {
|
||||
backupNovel.cover = APP_STORAGE_URI + backupNovel.cover;
|
||||
}
|
||||
|
||||
await _restoreNovelAndChapters(backupNovel);
|
||||
novelCount++;
|
||||
} catch (error: any) {
|
||||
failedCount++;
|
||||
const novelName =
|
||||
item.path.split('/').pop()?.replace('.json', '') || 'Unknown';
|
||||
showToast(
|
||||
getString('backupScreen.novelRestoreFailed', {
|
||||
novelName: novelName,
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
if (!backupNovel.cover?.startsWith('http')) {
|
||||
backupNovel.cover = APP_STORAGE_URI + backupNovel.cover;
|
||||
}
|
||||
|
||||
await _restoreNovelAndChapters(backupNovel);
|
||||
novelCount++;
|
||||
} catch {
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.novelDirectoryReadFailed', {
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
failedSectionCount++;
|
||||
}
|
||||
}
|
||||
if (failedCount > 0) {
|
||||
showToast(
|
||||
getString('backupScreen.novelsRestoredWithErrors', {
|
||||
count: novelCount,
|
||||
failedCount: failedCount,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
showToast(getString('backupScreen.novelsRestored', { count: novelCount }));
|
||||
}
|
||||
|
||||
// categories
|
||||
showToast(getString('backupScreen.restoringCategories'));
|
||||
if (manifest.sections.library) {
|
||||
updateRestoreProgress(
|
||||
setMeta,
|
||||
getString('backupScreen.restoringCategories'),
|
||||
);
|
||||
}
|
||||
const categoryFilePath = cacheDirPath + '/' + BackupEntryName.CATEGORY;
|
||||
let categoryCount = 0;
|
||||
let failedCategoryCount = 0;
|
||||
|
||||
if (!(await NativeFile.exists(categoryFilePath))) {
|
||||
showToast(getString('backupScreen.categoryFileNotFound'));
|
||||
if (!manifest.sections.library) {
|
||||
// Intentionally omitted from this backup.
|
||||
} else if (!(await NativeFile.exists(categoryFilePath))) {
|
||||
failedSectionCount++;
|
||||
} else {
|
||||
try {
|
||||
const fileContent = await NativeFile.readFile(categoryFilePath);
|
||||
const categories: BackupCategory[] = JSON.parse(fileContent);
|
||||
|
||||
for (const category of categories) {
|
||||
for (const [index, category] of categories.entries()) {
|
||||
updateRestoreProgress(
|
||||
setMeta,
|
||||
getString('backupScreen.restoringCategoriesProgress', {
|
||||
current: index + 1,
|
||||
total: categories.length,
|
||||
}),
|
||||
);
|
||||
try {
|
||||
_restoreCategory(category);
|
||||
await _restoreCategory(category);
|
||||
categoryCount++;
|
||||
} catch (error: any) {
|
||||
} catch {
|
||||
failedCategoryCount++;
|
||||
showToast(
|
||||
getString('backupScreen.categoryRestoreFailed', {
|
||||
categoryName: category.name || category.id.toString(),
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.categoryFileReadFailed', {
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
failedSectionCount++;
|
||||
}
|
||||
}
|
||||
if (failedCategoryCount > 0) {
|
||||
showToast(
|
||||
getString('backupScreen.categoriesRestoredWithErrors', {
|
||||
count: categoryCount,
|
||||
failedCount: failedCategoryCount,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
showToast(
|
||||
getString('backupScreen.categoriesRestored', {
|
||||
count: categoryCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// settings
|
||||
showToast(getString('backupScreen.restoringSettings'));
|
||||
if (manifest.sections.settings) {
|
||||
updateRestoreProgress(setMeta, getString('backupScreen.restoringSettings'));
|
||||
}
|
||||
const settingsFilePath = cacheDirPath + '/' + BackupEntryName.SETTING;
|
||||
let settingsRestored = !manifest.sections.settings;
|
||||
|
||||
if (!(await NativeFile.exists(settingsFilePath))) {
|
||||
showToast(getString('backupScreen.settingsFileNotFound'));
|
||||
if (!manifest.sections.settings) {
|
||||
// Intentionally omitted from this backup.
|
||||
} else if (!(await NativeFile.exists(settingsFilePath))) {
|
||||
// Reported as a settings warning in the completion summary.
|
||||
} else {
|
||||
try {
|
||||
const fileContent = await NativeFile.readFile(settingsFilePath);
|
||||
const settingsData = JSON.parse(fileContent);
|
||||
restoreMMKVData(settingsData);
|
||||
showToast(getString('backupScreen.settingsRestored'));
|
||||
} catch (error: any) {
|
||||
showToast(
|
||||
getString('backupScreen.settingsRestoreFailed', {
|
||||
error: error?.message || String(error),
|
||||
}),
|
||||
);
|
||||
settingsRestored = true;
|
||||
} catch {
|
||||
// Included in the completion warning below.
|
||||
}
|
||||
}
|
||||
|
||||
// installed plugin registry
|
||||
if (manifest.formatVersion === 2 && manifest.sections.plugins) {
|
||||
const pluginMetadataPath =
|
||||
cacheDirPath + '/' + BackupEntryName.PLUGIN_METADATA;
|
||||
if (!(await NativeFile.exists(pluginMetadataPath))) {
|
||||
failedSectionCount++;
|
||||
} else {
|
||||
try {
|
||||
const installedPlugins = await NativeFile.readFile(pluginMetadataPath);
|
||||
JSON.parse(installedPlugins);
|
||||
MMKVStorage.set(INSTALLED_PLUGINS_KEY, installedPlugins);
|
||||
} catch {
|
||||
failedSectionCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
novelCount,
|
||||
failedNovelCount: failedCount,
|
||||
categoryCount,
|
||||
failedCategoryCount,
|
||||
settingsRestored,
|
||||
failedSectionCount,
|
||||
pluginIds: [...pluginIds],
|
||||
manifest,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -83,13 +83,15 @@ export const exportEpub = async (
|
||||
{ replaceIfDestinationExists: true },
|
||||
);
|
||||
|
||||
const completionText = getString('novelScreen.epub.exportSuccess', {
|
||||
chapters: result.chapterCount.toString(),
|
||||
});
|
||||
updateProgress(meta => ({
|
||||
...meta,
|
||||
isRunning: false,
|
||||
progress: 1,
|
||||
progressText: getString('novelScreen.epub.exportSuccess', {
|
||||
chapters: result.chapterCount.toString(),
|
||||
}),
|
||||
progressText: completionText,
|
||||
completionText,
|
||||
}));
|
||||
} catch (error) {
|
||||
updateProgress(meta => ({
|
||||
|
||||
@@ -210,6 +210,7 @@ export const migrateNovel = async (
|
||||
data: {
|
||||
novelName: toNovel.name,
|
||||
novelId: toNovel.id,
|
||||
pluginId: toNovel.pluginId,
|
||||
chapters: chaptersToDownload,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -78,6 +78,7 @@ const updateNovelTotalPages = async (novelId: number, totalPages: number) => {
|
||||
* Distinguishes between new chapters (triggers download) and existing chapters (updates metadata).
|
||||
*/
|
||||
const updateNovelChapters = async (
|
||||
pluginId: string,
|
||||
novelName: string,
|
||||
novelId: number,
|
||||
chapters: ChapterItem[],
|
||||
@@ -144,6 +145,7 @@ const updateNovelChapters = async (
|
||||
data: {
|
||||
novelName,
|
||||
novelId,
|
||||
pluginId,
|
||||
chapters: insertedNewChapters.map(insertedChapter => ({
|
||||
chapterId: insertedChapter.id,
|
||||
chapterName:
|
||||
@@ -196,6 +198,7 @@ const updateNovel = async (
|
||||
await updateNovelTotalPages(novelId, novel.totalPages);
|
||||
}
|
||||
await updateNovelChapters(
|
||||
pluginId,
|
||||
novel.name,
|
||||
novelId,
|
||||
novel.chapters || [],
|
||||
@@ -217,6 +220,7 @@ const updateNovel = async (
|
||||
String(oldTotalPages),
|
||||
);
|
||||
await updateNovelChapters(
|
||||
pluginId,
|
||||
novel.name,
|
||||
novelId,
|
||||
sourcePage.chapters || [],
|
||||
@@ -232,6 +236,7 @@ const updateNovel = async (
|
||||
try {
|
||||
const sourcePage = await fetchPage(pluginId, novelPath, String(page));
|
||||
await updateNovelChapters(
|
||||
pluginId,
|
||||
novel.name,
|
||||
novelId,
|
||||
sourcePage.chapters || [],
|
||||
@@ -260,6 +265,7 @@ const updateNovelPage = async (
|
||||
const sourcePage = await fetchPage(pluginId, novelPath, page);
|
||||
|
||||
await updateNovelChapters(
|
||||
pluginId,
|
||||
novelName,
|
||||
novelId,
|
||||
sourcePage.chapters || [],
|
||||
|
||||
Reference in New Issue
Block a user