forked from akai/readest
This commit is contained in:
Generated
+56
-115
@@ -29,7 +29,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tauri-build",
|
||||
"tauri-plugin-cli",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-dialog",
|
||||
@@ -56,9 +56,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
@@ -310,7 +310,7 @@ dependencies = [
|
||||
"polling",
|
||||
"rustix",
|
||||
"slab",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -368,7 +368,7 @@ dependencies = [
|
||||
"rustix",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -425,9 +425,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
@@ -435,7 +435,7 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1217,7 +1217,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1455,7 +1455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1916,9 +1916,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
version = "0.32.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
@@ -2283,7 +2283,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.62.0",
|
||||
"windows-core 0.62.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2818,9 +2818,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@@ -3309,9 +3309,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
version = "0.37.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -3791,7 +3791,7 @@ dependencies = [
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4269,9 +4269,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.2"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -4281,9 +4281,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.10"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -4479,7 +4479,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4565,7 +4565,7 @@ version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4696,9 +4696,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.226"
|
||||
version = "1.0.227"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
|
||||
checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@@ -4718,18 +4718,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.226"
|
||||
version = "1.0.227"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
|
||||
checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.226"
|
||||
version = "1.0.227"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
|
||||
checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5327,11 +5327,11 @@ dependencies = [
|
||||
"specta",
|
||||
"swift-rs",
|
||||
"tauri",
|
||||
"tauri-build 2.4.1",
|
||||
"tauri-build",
|
||||
"tauri-macros",
|
||||
"tauri-runtime",
|
||||
"tauri-runtime-wry",
|
||||
"tauri-utils 2.7.0",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.16",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -5361,29 +5361,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-codegen",
|
||||
"tauri-utils 2.7.0",
|
||||
"tauri-winres",
|
||||
"toml 0.9.7",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
"dirs",
|
||||
"glob",
|
||||
"heck 0.5.0",
|
||||
"json-patch",
|
||||
"schemars 0.8.22",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tauri-utils",
|
||||
"tauri-winres",
|
||||
"toml 0.9.7",
|
||||
"walkdir",
|
||||
@@ -5406,7 +5384,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"syn 2.0.106",
|
||||
"tauri-utils 2.7.0",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.16",
|
||||
"time",
|
||||
"url",
|
||||
@@ -5423,7 +5401,7 @@ dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
"tauri-codegen",
|
||||
"tauri-utils 2.7.0",
|
||||
"tauri-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5438,7 +5416,7 @@ dependencies = [
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tauri-utils",
|
||||
"toml 0.9.7",
|
||||
"walkdir",
|
||||
]
|
||||
@@ -5471,7 +5449,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.16",
|
||||
"tracing",
|
||||
"url",
|
||||
@@ -5513,7 +5491,7 @@ dependencies = [
|
||||
"serde_repr",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.16",
|
||||
"toml 0.9.7",
|
||||
"url",
|
||||
@@ -5793,7 +5771,7 @@ dependencies = [
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.7.0",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.16",
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
@@ -5818,7 +5796,7 @@ dependencies = [
|
||||
"softbuffer",
|
||||
"tao",
|
||||
"tauri-runtime",
|
||||
"tauri-utils 2.7.0",
|
||||
"tauri-utils",
|
||||
"tracing",
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
@@ -5868,43 +5846,6 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"ctor",
|
||||
"dunce",
|
||||
"glob",
|
||||
"html5ever",
|
||||
"http",
|
||||
"infer",
|
||||
"json-patch",
|
||||
"kuchikiki",
|
||||
"log",
|
||||
"memchr",
|
||||
"phf 0.11.3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"schemars 0.8.22",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde-untagged",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"swift-rs",
|
||||
"thiserror 2.0.16",
|
||||
"toml 0.9.7",
|
||||
"url",
|
||||
"urlpattern",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-winres"
|
||||
version = "0.3.3"
|
||||
@@ -5925,7 +5866,7 @@ dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6853,7 +6794,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6914,9 +6855,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.0"
|
||||
version = "0.62.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
|
||||
checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
@@ -6938,9 +6879,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
version = "0.60.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6949,9 +6890,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
version = "0.59.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -7060,14 +7001,14 @@ version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.3",
|
||||
"windows-targets 0.53.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
|
||||
checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f"
|
||||
dependencies = [
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
@@ -7105,11 +7046,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.3"
|
||||
version = "0.53.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-link 0.2.0",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
@@ -7131,9 +7072,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-version"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb"
|
||||
checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e"
|
||||
dependencies = [
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
members = [
|
||||
"apps/readest-app/src-tauri",
|
||||
"packages/tauri/crates/tauri",
|
||||
"packages/tauri/crates/tauri-utils",
|
||||
"packages/tauri/crates/tauri-build",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
@@ -31,3 +33,5 @@ rust-version = "1.77.2"
|
||||
|
||||
[patch.crates-io]
|
||||
tauri = { path = "packages/tauri/crates/tauri" }
|
||||
tauri-utils = { path = "packages/tauri/crates/tauri-utils" }
|
||||
tauri-build = { path = "packages/tauri/crates/tauri-build" }
|
||||
|
||||
@@ -590,5 +590,27 @@
|
||||
"Single Page": "صفحة واحدة",
|
||||
"Auto Spread": "انتشار تلقائي",
|
||||
"Fit Page": "تناسب الصفحة",
|
||||
"Fit Width": "تناسب العرض"
|
||||
"Fit Width": "تناسب العرض",
|
||||
"Failed to select directory": "فشل في اختيار الدليل",
|
||||
"The new data directory must be different from the current one.": "يجب أن يكون دليل البيانات الجديد مختلفًا عن الدليل الحالي.",
|
||||
"Migration failed: {{error}}": "فشل في الترحيل: {{error}}",
|
||||
"Change Data Location": "تغيير موقع البيانات",
|
||||
"Current Data Location": "موقع البيانات الحالي",
|
||||
"Total size: {{size}}": "الحجم الكلي: {{size}}",
|
||||
"Calculating file info...": "جارٍ حساب معلومات الملف...",
|
||||
"New Data Location": "موقع البيانات الجديد",
|
||||
"Choose Different Folder": "اختر مجلدًا مختلفًا",
|
||||
"Choose New Folder": "اختر مجلدًا جديدًا",
|
||||
"Migrating data...": "جارٍ ترحيل البيانات...",
|
||||
"Copying: {{file}}": "جارٍ نسخ: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} من {{total}} ملف",
|
||||
"Migration completed successfully!": "اكتمل الترحيل بنجاح!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "تم نقل بياناتك إلى الموقع الجديد. يرجى إعادة تشغيل التطبيق لإكمال العملية.",
|
||||
"Migration failed": "فشل في الترحيل",
|
||||
"Important Notice": "إشعار مهم",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "سيؤدي ذلك إلى نقل جميع بيانات التطبيق الخاصة بك إلى الموقع الجديد. تأكد من أن الوجهة تحتوي على مساحة خالية كافية.",
|
||||
"Restart App": "إعادة تشغيل التطبيق",
|
||||
"Start Migration": "بدء الترحيل",
|
||||
"Advanced Settings": "إعدادات متقدمة",
|
||||
"File count: {{size}}": "عدد الملفات: {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "একক পৃষ্ঠা",
|
||||
"Auto Spread": "অটো স্প্রেড",
|
||||
"Fit Page": "ফিট পৃষ্ঠা",
|
||||
"Fit Width": "ফিট প্রস্থ"
|
||||
"Fit Width": "ফিট প্রস্থ",
|
||||
"Failed to select directory": "ডিরেক্টরি নির্বাচন করতে ব্যর্থ",
|
||||
"The new data directory must be different from the current one.": "নতুন ডেটা ডিরেক্টরি বর্তমানটির থেকে আলাদা হতে হবে।",
|
||||
"Migration failed: {{error}}": "মাইগ্রেশন ব্যর্থ হয়েছে: {{error}}",
|
||||
"Change Data Location": "ডেটা অবস্থান পরিবর্তন করুন",
|
||||
"Current Data Location": "বর্তমান ডেটা অবস্থান",
|
||||
"Total size: {{size}}": "মোট আকার: {{size}}",
|
||||
"Calculating file info...": "ফাইলের তথ্য গণনা করা হচ্ছে...",
|
||||
"New Data Location": "নতুন ডেটা অবস্থান",
|
||||
"Choose Different Folder": "ভিন্ন ফোল্ডার নির্বাচন করুন",
|
||||
"Choose New Folder": "নতুন ফোল্ডার নির্বাচন করুন",
|
||||
"Migrating data...": "ডেটা স্থানান্তরিত হচ্ছে...",
|
||||
"Copying: {{file}}": "কপি করা হচ্ছে: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} এর {{total}} ফাইল",
|
||||
"Migration completed successfully!": "মাইগ্রেশন সফলভাবে সম্পন্ন হয়েছে!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "আপনার ডেটা নতুন অবস্থানে স্থানান্তরিত হয়েছে। প্রক্রিয়া সম্পন্ন করতে দয়া করে অ্যাপ্লিকেশনটি পুনরায় চালু করুন।",
|
||||
"Migration failed": "মাইগ্রেশন ব্যর্থ হয়েছে",
|
||||
"Important Notice": "গুরুতর বিজ্ঞপ্তি",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "এটি আপনার সমস্ত অ্যাপ ডেটা নতুন অবস্থানে স্থানান্তরিত করবে। নিশ্চিত করুন যে গন্তব্যে পর্যাপ্ত ফ্রি স্পেস রয়েছে।",
|
||||
"Restart App": "অ্যাপ পুনরায় চালু করুন",
|
||||
"Start Migration": "মাইগ্রেশন শুরু করুন",
|
||||
"Advanced Settings": "উন্নত সেটিংস",
|
||||
"File count: {{size}}": "ফাইলের সংখ্যা: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "དེབ་གཅིག",
|
||||
"Auto Spread": "རང་འགུལ་སྤྲོད།",
|
||||
"Fit Page": "དེབ་འདེམས་པ།",
|
||||
"Fit Width": "ཁྱབ་སྒྲིག་འདེམས་པ།"
|
||||
"Fit Width": "ཁྱབ་སྒྲིག་འདེམས་པ།",
|
||||
"Failed to select directory": "གནས་ས་འདེམས་པ་བྱས་མ་ཐུབ།",
|
||||
"The new data directory must be different from the current one.": "གསར་བཅས་སྐོར་འདེམས་པ་གནས་ས་དང་མཉམ་འབྱུང་བར་བྱས་མ་ཐུབ།",
|
||||
"Migration failed: {{error}}": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།",
|
||||
"Change Data Location": "གསར་བཅས་སྐོར་འདེམས་པ།",
|
||||
"Current Data Location": "ད་ལྟ་བཅས་སྐོར་འདེམས་པ།",
|
||||
"Total size: {{size}}": "དངོས་གནས་བཅས་: {{size}}",
|
||||
"Calculating file info...": "དེབ་གནས་བཅས་པའི་གདམ་ཁ་བཟོ་བྱས་མ་ཐུབ།",
|
||||
"New Data Location": "གསར་བཅས་སྐོར་འདེམས་པ།",
|
||||
"Choose Different Folder": "གཞན་དེབ་སྣོད་བཀར་བ།",
|
||||
"Choose New Folder": "གསར་བཅས་སྣོད་བཀར་བ།",
|
||||
"Migrating data...": "དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"Copying: {{file}}": "དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"{{current}} of {{total}} files": "{{current}} དང་ {{total}} དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"Migration completed successfully!": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "ཁྱོད་ཀྱི་དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"Migration failed": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།",
|
||||
"Important Notice": "དོན་གཞི་བརྗེ་བ།",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "འདི་ནས་ཁྱོད་ཀྱི་ཨང་གཏོད་དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"Restart App": "དེབ་ཀྱི་སྤྱོད་བྱས་མ་ཐུབ།",
|
||||
"Start Migration": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།",
|
||||
"Advanced Settings": "དབང་བསྐྱོད་སྒྲིག་སྟངས།",
|
||||
"File count: {{size}}": "དེབ་གནས་བཅས་པའི་ཨང་། {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "Einzelne Seite",
|
||||
"Auto Spread": "Automatische Verbreitung",
|
||||
"Fit Page": "Seite anpassen",
|
||||
"Fit Width": "Breite anpassen"
|
||||
"Fit Width": "Breite anpassen",
|
||||
"Failed to select directory": "Fehler beim Auswählen des Verzeichnisses",
|
||||
"The new data directory must be different from the current one.": "Das neue Datenverzeichnis muss sich vom aktuellen unterscheiden.",
|
||||
"Migration failed: {{error}}": "Migration fehlgeschlagen: {{error}}",
|
||||
"Change Data Location": "Datenstandort ändern",
|
||||
"Current Data Location": "Aktueller Datenstandort",
|
||||
"Total size: {{size}}": "Gesamtgröße: {{size}}",
|
||||
"Calculating file info...": "Dateiinformationen werden berechnet...",
|
||||
"New Data Location": "Neuer Datenstandort",
|
||||
"Choose Different Folder": "Anderen Ordner wählen",
|
||||
"Choose New Folder": "Neuen Ordner wählen",
|
||||
"Migrating data...": "Daten werden migriert...",
|
||||
"Copying: {{file}}": "Kopiere: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} von {{total}} Dateien",
|
||||
"Migration completed successfully!": "Migration erfolgreich abgeschlossen!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Ihre Daten wurden an den neuen Speicherort verschoben. Bitte starten Sie die Anwendung neu, um den Vorgang abzuschließen.",
|
||||
"Migration failed": "Migration fehlgeschlagen",
|
||||
"Important Notice": "Wichtiger Hinweis",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Dies wird alle Ihre App-Daten an den neuen Speicherort verschieben. Stellen Sie sicher, dass das Ziel über ausreichend freien Speicherplatz verfügt.",
|
||||
"Restart App": "App neu starten",
|
||||
"Start Migration": "Migration starten",
|
||||
"Advanced Settings": "Erweiterte Einstellungen",
|
||||
"File count: {{size}}": "Dateianzahl: {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "Μοναδική σελίδα",
|
||||
"Auto Spread": "Αυτόματη εξάπλωση",
|
||||
"Fit Page": "Προσαρμογή σελίδας",
|
||||
"Fit Width": "Προσαρμογή πλάτους"
|
||||
"Fit Width": "Προσαρμογή πλάτους",
|
||||
"Failed to select directory": "Αποτυχία επιλογής καταλόγου",
|
||||
"The new data directory must be different from the current one.": "Ο νέος κατάλογος δεδομένων πρέπει να είναι διαφορετικός από τον τρέχοντα.",
|
||||
"Migration failed: {{error}}": "Η μετανάστευση απέτυχε: {{error}}",
|
||||
"Change Data Location": "Αλλαγή τοποθεσίας δεδομένων",
|
||||
"Current Data Location": "Τρέχουσα τοποθεσία δεδομένων",
|
||||
"Total size: {{size}}": "Συνολικό μέγεθος: {{size}}",
|
||||
"Calculating file info...": "Υπολογισμός πληροφοριών αρχείου...",
|
||||
"New Data Location": "Νέα τοποθεσία δεδομένων",
|
||||
"Choose Different Folder": "Επιλέξτε διαφορετικό φάκελο",
|
||||
"Choose New Folder": "Επιλέξτε νέο φάκελο",
|
||||
"Migrating data...": "Μεταφορά δεδομένων...",
|
||||
"Copying: {{file}}": "Αντιγραφή: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} από {{total}} αρχεία",
|
||||
"Migration completed successfully!": "Η μετανάστευση ολοκληρώθηκε με επιτυχία!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Τα δεδομένα σας έχουν μεταφερθεί στη νέα τοποθεσία. Παρακαλώ επανεκκινήστε την εφαρμογή για να ολοκληρώσετε τη διαδικασία.",
|
||||
"Migration failed": "Η μετανάστευση απέτυχε",
|
||||
"Important Notice": "Σημαντική ειδοποίηση",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Αυτό θα μεταφέρει όλα τα δεδομένα της εφαρμογής σας στη νέα τοποθεσία. Βεβαιωθείτε ότι ο προορισμός έχει αρκετό ελεύθερο χώρο.",
|
||||
"Restart App": "Επανεκκίνηση εφαρμογής",
|
||||
"Start Migration": "Έναρξη μετανάστευσης",
|
||||
"Advanced Settings": "Προηγμένες ρυθμίσεις",
|
||||
"File count: {{size}}": "Αριθμός αρχείων: {{size}}"
|
||||
}
|
||||
|
||||
@@ -578,5 +578,27 @@
|
||||
"Single Page": "Página Única",
|
||||
"Auto Spread": "Distribución Automática",
|
||||
"Fit Page": "Ajustar Página",
|
||||
"Fit Width": "Ajustar Ancho"
|
||||
"Fit Width": "Ajustar Ancho",
|
||||
"Failed to select directory": "Error al seleccionar el directorio",
|
||||
"The new data directory must be different from the current one.": "El nuevo directorio de datos debe ser diferente del actual.",
|
||||
"Migration failed: {{error}}": "La migración falló: {{error}}",
|
||||
"Change Data Location": "Cambiar Ubicación de Datos",
|
||||
"Current Data Location": "Ubicación Actual de Datos",
|
||||
"Total size: {{size}}": "Tamaño total: {{size}}",
|
||||
"Calculating file info...": "Calculando información del archivo...",
|
||||
"New Data Location": "Nueva Ubicación de Datos",
|
||||
"Choose Different Folder": "Elegir Carpeta Diferente",
|
||||
"Choose New Folder": "Elegir Nueva Carpeta",
|
||||
"Migrating data...": "Migrando datos...",
|
||||
"Copying: {{file}}": "Copiando: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} de {{total}} archivos",
|
||||
"Migration completed successfully!": "¡Migración completada con éxito!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Tus datos han sido movidos a la nueva ubicación. Por favor, reinicia la aplicación para completar el proceso.",
|
||||
"Migration failed": "La migración falló",
|
||||
"Important Notice": "Aviso Importante",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Esto moverá todos los datos de tu aplicación a la nueva ubicación. Asegúrate de que el destino tenga suficiente espacio libre.",
|
||||
"Restart App": "Reiniciar Aplicación",
|
||||
"Start Migration": "Iniciar Migración",
|
||||
"Advanced Settings": "Configuraciones Avanzadas",
|
||||
"File count: {{size}}": "Número de archivos: {{size}}"
|
||||
}
|
||||
|
||||
@@ -578,5 +578,27 @@
|
||||
"Single Page": "Page Unique",
|
||||
"Auto Spread": "Répartition Automatique",
|
||||
"Fit Page": "Ajuster la Page",
|
||||
"Fit Width": "Ajuster la Largeur"
|
||||
"Fit Width": "Ajuster la Largeur",
|
||||
"Failed to select directory": "Échec de la sélection du répertoire",
|
||||
"The new data directory must be different from the current one.": "Le nouveau répertoire de données doit être différent de l'actuel.",
|
||||
"Migration failed: {{error}}": "La migration a échoué : {{error}}",
|
||||
"Change Data Location": "Changer l'Emplacement des Données",
|
||||
"Current Data Location": "Emplacement Actuel des Données",
|
||||
"Total size: {{size}}": "Taille totale : {{size}}",
|
||||
"Calculating file info...": "Calcul des informations sur le fichier...",
|
||||
"New Data Location": "Nouvel Emplacement des Données",
|
||||
"Choose Different Folder": "Choisir un Dossier Différent",
|
||||
"Choose New Folder": "Choisir un Nouveau Dossier",
|
||||
"Migrating data...": "Migration des données...",
|
||||
"Copying: {{file}}": "Copie : {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} sur {{total}} fichiers",
|
||||
"Migration completed successfully!": "Migration terminée avec succès !",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Vos données ont été déplacées vers le nouvel emplacement. Veuillez redémarrer l'application pour terminer le processus.",
|
||||
"Migration failed": "La migration a échoué",
|
||||
"Important Notice": "Avis Important",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Cela déplacera toutes vos données d'application vers le nouvel emplacement. Assurez-vous que la destination dispose de suffisamment d'espace libre.",
|
||||
"Restart App": "Redémarrer l'Application",
|
||||
"Start Migration": "Démarrer la Migration",
|
||||
"Advanced Settings": "Paramètres Avancés",
|
||||
"File count: {{size}}": "Nombre de fichiers : {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "एकल पृष्ठ",
|
||||
"Auto Spread": "स्वचालित फैलाव",
|
||||
"Fit Page": "पृष्ठ में फिट करें",
|
||||
"Fit Width": "चौड़ाई में फिट करें"
|
||||
"Fit Width": "चौड़ाई में फिट करें",
|
||||
"Failed to select directory": "निर्देशिका का चयन करने में विफल",
|
||||
"The new data directory must be different from the current one.": "नया डेटा निर्देशिका वर्तमान से भिन्न होना चाहिए।",
|
||||
"Migration failed: {{error}}": "माइग्रेशन विफल: {{error}}",
|
||||
"Change Data Location": "डेटा स्थान बदलें",
|
||||
"Current Data Location": "वर्तमान डेटा स्थान",
|
||||
"Total size: {{size}}": "कुल आकार: {{size}}",
|
||||
"Calculating file info...": "फ़ाइल जानकारी की गणना कर रहे हैं...",
|
||||
"New Data Location": "नया डेटा स्थान",
|
||||
"Choose Different Folder": "विभिन्न फ़ोल्डर चुनें",
|
||||
"Choose New Folder": "नया फ़ोल्डर चुनें",
|
||||
"Migrating data...": "डेटा माइग्रेट कर रहे हैं...",
|
||||
"Copying: {{file}}": "कॉपी कर रहे हैं: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} में से {{total}} फ़ाइलें",
|
||||
"Migration completed successfully!": "माइग्रेशन सफलतापूर्वक पूरा हुआ!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "आपका डेटा नए स्थान पर स्थानांतरित कर दिया गया है। कृपया प्रक्रिया को पूरा करने के लिए एप्लिकेशन को पुनरारंभ करें।",
|
||||
"Migration failed": "माइग्रेशन विफल",
|
||||
"Important Notice": "महत्वपूर्ण सूचना",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "यह आपके सभी ऐप डेटा को नए स्थान पर स्थानांतरित कर देगा। सुनिश्चित करें कि गंतव्य में पर्याप्त खाली स्थान है।",
|
||||
"Restart App": "एप्लिकेशन पुनरारंभ करें",
|
||||
"Start Migration": "माइग्रेशन प्रारंभ करें",
|
||||
"Advanced Settings": "उन्नत सेटिंग्स",
|
||||
"File count: {{size}}": "फ़ाइलों की संख्या: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "Halaman Tunggal",
|
||||
"Auto Spread": "Penyebaran Otomatis",
|
||||
"Fit Page": "Sesuaikan Halaman",
|
||||
"Fit Width": "Sesuaikan Lebar"
|
||||
"Fit Width": "Sesuaikan Lebar",
|
||||
"Failed to select directory": "Gagal memilih direktori",
|
||||
"The new data directory must be different from the current one.": "Direktori data baru harus berbeda dari yang saat ini.",
|
||||
"Migration failed: {{error}}": "Migrasi gagal: {{error}}",
|
||||
"Change Data Location": "Ubah Lokasi Data",
|
||||
"Current Data Location": "Lokasi Data Saat Ini",
|
||||
"Total size: {{size}}": "Ukuran total: {{size}}",
|
||||
"Calculating file info...": "Menghitung informasi file...",
|
||||
"New Data Location": "Lokasi Data Baru",
|
||||
"Choose Different Folder": "Pilih Folder Berbeda",
|
||||
"Choose New Folder": "Pilih Folder Baru",
|
||||
"Migrating data...": "Migrasi data...",
|
||||
"Copying: {{file}}": "Menyalin: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} dari {{total}} file",
|
||||
"Migration completed successfully!": "Migrasi selesai dengan sukses!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Data Anda telah dipindahkan ke lokasi baru. Silakan restart aplikasi untuk menyelesaikan proses.",
|
||||
"Migration failed": "Migrasi gagal",
|
||||
"Important Notice": "Pemberitahuan Penting",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Ini akan memindahkan semua data aplikasi Anda ke lokasi baru. Pastikan tujuan memiliki cukup ruang kosong.",
|
||||
"Restart App": "Restart Aplikasi",
|
||||
"Start Migration": "Mulai Migrasi",
|
||||
"Advanced Settings": "Pengaturan Lanjutan",
|
||||
"File count: {{size}}": "Jumlah file: {{size}}"
|
||||
}
|
||||
|
||||
@@ -578,5 +578,27 @@
|
||||
"Single Page": "Pagina singola",
|
||||
"Auto Spread": "Distribuzione automatica",
|
||||
"Fit Page": "Adatta pagina",
|
||||
"Fit Width": "Adatta larghezza"
|
||||
"Fit Width": "Adatta larghezza",
|
||||
"Failed to select directory": "Impossibile selezionare la directory",
|
||||
"The new data directory must be different from the current one.": "La nuova directory dei dati deve essere diversa da quella attuale.",
|
||||
"Migration failed: {{error}}": "Migrzione fallita: {{error}}",
|
||||
"Change Data Location": "Cambia posizione dei dati",
|
||||
"Current Data Location": "Posizione attuale dei dati",
|
||||
"Total size: {{size}}": "Dimensione totale: {{size}}",
|
||||
"Calculating file info...": "Calcolo informazioni file...",
|
||||
"New Data Location": "Nuova posizione dei dati",
|
||||
"Choose Different Folder": "Scegli una cartella diversa",
|
||||
"Choose New Folder": "Scegli una nuova cartella",
|
||||
"Migrating data...": "Migrando dati...",
|
||||
"Copying: {{file}}": "Copia in corso: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} di {{total}} file",
|
||||
"Migration completed successfully!": "Migrzione completata con successo!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "I tuoi dati sono stati spostati nella nuova posizione. Riavvia l'applicazione per completare il processo.",
|
||||
"Migration failed": "Migrzione fallita",
|
||||
"Important Notice": "Avviso Importante",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Questo sposterà tutti i dati dell'app nella nuova posizione. Assicurati che la destinazione abbia spazio libero sufficiente.",
|
||||
"Restart App": "Riavvia App",
|
||||
"Start Migration": "Inizia Migrazione",
|
||||
"Advanced Settings": "Impostazioni Avanzate",
|
||||
"File count: {{size}}": "Conteggio file: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "シングルページ",
|
||||
"Auto Spread": "自動スプレッド",
|
||||
"Fit Page": "ページに合わせる",
|
||||
"Fit Width": "幅に合わせる"
|
||||
"Fit Width": "幅に合わせる",
|
||||
"Failed to select directory": "ディレクトリの選択に失敗しました",
|
||||
"The new data directory must be different from the current one.": "新しいデータディレクトリは現在のものと異なる必要があります。",
|
||||
"Migration failed: {{error}}": "移行に失敗しました: {{error}}",
|
||||
"Change Data Location": "データの場所を変更",
|
||||
"Current Data Location": "現在のデータの場所",
|
||||
"Total size: {{size}}": "合計サイズ: {{size}}",
|
||||
"Calculating file info...": "ファイル情報を計算中...",
|
||||
"New Data Location": "新しいデータの場所",
|
||||
"Choose Different Folder": "別のフォルダーを選択",
|
||||
"Choose New Folder": "新しいフォルダーを選択",
|
||||
"Migrating data...": "データを移行中...",
|
||||
"Copying: {{file}}": "コピー中: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} / {{total}} ファイル",
|
||||
"Migration completed successfully!": "移行が成功しました!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "データは新しい場所に移動されました。プロセスを完了するにはアプリケーションを再起動してください。",
|
||||
"Migration failed": "移行に失敗しました",
|
||||
"Important Notice": "重要なお知らせ",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "これにより、すべてのアプリデータが新しい場所に移動されます。宛先に十分な空き容量があることを確認してください。",
|
||||
"Restart App": "アプリを再起動",
|
||||
"Start Migration": "移行を開始",
|
||||
"Advanced Settings": "詳細設定",
|
||||
"File count: {{size}}": "ファイル数: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "단일 페이지",
|
||||
"Auto Spread": "자동 스프레드",
|
||||
"Fit Page": "페이지에 맞춤",
|
||||
"Fit Width": "너비에 맞춤"
|
||||
"Fit Width": "너비에 맞춤",
|
||||
"Failed to select directory": "디렉토리 선택 실패",
|
||||
"The new data directory must be different from the current one.": "새 데이터 디렉토리는 현재 디렉토리와 달라야 합니다.",
|
||||
"Migration failed: {{error}}": "마이그레이션 실패: {{error}}",
|
||||
"Change Data Location": "데이터 위치 변경",
|
||||
"Current Data Location": "현재 데이터 위치",
|
||||
"Total size: {{size}}": "총 크기: {{size}}",
|
||||
"Calculating file info...": "파일 정보 계산 중...",
|
||||
"New Data Location": "새 데이터 위치",
|
||||
"Choose Different Folder": "다른 폴더 선택",
|
||||
"Choose New Folder": "새 폴더 선택",
|
||||
"Migrating data...": "데이터 마이그레이션 중...",
|
||||
"Copying: {{file}}": "복사 중: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} / {{total}} 파일",
|
||||
"Migration completed successfully!": "마이그레이션이 성공적으로 완료되었습니다!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "데이터가 새 위치로 이동되었습니다. 프로세스를 완료하려면 애플리케이션을 재시작하십시오.",
|
||||
"Migration failed": "마이그레이션 실패",
|
||||
"Important Notice": "중요한 공지",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "이 작업은 모든 앱 데이터를 새 위치로 이동합니다. 대상에 충분한 여유 공간이 있는지 확인하십시오.",
|
||||
"Restart App": "앱 재시작",
|
||||
"Start Migration": "마이그레이션 시작",
|
||||
"Advanced Settings": "고급 설정",
|
||||
"File count: {{size}}": "파일 수: {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "Enkele Pagina",
|
||||
"Auto Spread": "Automatische Verspreiding",
|
||||
"Fit Page": "Pagina Aanpassen",
|
||||
"Fit Width": "Breedte Aanpassen"
|
||||
"Fit Width": "Breedte Aanpassen",
|
||||
"Failed to select directory": "Selecteren van map is mislukt",
|
||||
"The new data directory must be different from the current one.": "De nieuwe gegevensmap moet anders zijn dan de huidige.",
|
||||
"Migration failed: {{error}}": "Migratie mislukt: {{error}}",
|
||||
"Change Data Location": "Gegevenslocatie Wijzigen",
|
||||
"Current Data Location": "Huidige Gegevenslocatie",
|
||||
"Total size: {{size}}": "Totale grootte: {{size}}",
|
||||
"Calculating file info...": "Bestandinformatie wordt berekend...",
|
||||
"New Data Location": "Nieuwe Gegevenslocatie",
|
||||
"Choose Different Folder": "Kies Een Andere Map",
|
||||
"Choose New Folder": "Kies Nieuwe Map",
|
||||
"Migrating data...": "Gegevens worden gemigreerd...",
|
||||
"Copying: {{file}}": "Kopiëren: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} van {{total}} bestanden",
|
||||
"Migration completed successfully!": "Migratie succesvol voltooid!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Uw gegevens zijn naar de nieuwe locatie verplaatst. Start de applicatie opnieuw op om het proces te voltooien.",
|
||||
"Migration failed": "Migratie mislukt",
|
||||
"Important Notice": "Belangrijke Kennisgeving",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Dit zal al uw app-gegevens naar de nieuwe locatie verplaatsen. Zorg ervoor dat de bestemming voldoende vrije ruimte heeft.",
|
||||
"Restart App": "Herstart App",
|
||||
"Start Migration": "Start Migratie",
|
||||
"Advanced Settings": "Geavanceerde Instellingen",
|
||||
"File count: {{size}}": "Bestandsaantal: {{size}}"
|
||||
}
|
||||
|
||||
@@ -582,5 +582,27 @@
|
||||
"Single Page": "Pojedyncza Strona",
|
||||
"Auto Spread": "Automatyczne Rozprzestrzenianie",
|
||||
"Fit Page": "Dopasuj Stronę",
|
||||
"Fit Width": "Dopasuj Szerokość"
|
||||
"Fit Width": "Dopasuj Szerokość",
|
||||
"Failed to select directory": "Nie udało się wybrać katalogu",
|
||||
"The new data directory must be different from the current one.": "Nowy katalog danych musi różnić się od obecnego.",
|
||||
"Migration failed: {{error}}": "Migracja nie powiodła się: {{error}}",
|
||||
"Change Data Location": "Zmień lokalizację danych",
|
||||
"Current Data Location": "Bieżąca lokalizacja danych",
|
||||
"Total size: {{size}}": "Całkowity rozmiar: {{size}}",
|
||||
"Calculating file info...": "Obliczanie informacji o pliku...",
|
||||
"New Data Location": "Nowa lokalizacja danych",
|
||||
"Choose Different Folder": "Wybierz inny folder",
|
||||
"Choose New Folder": "Wybierz nowy folder",
|
||||
"Migrating data...": "Migracja danych...",
|
||||
"Copying: {{file}}": "Kopiowanie: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} z {{total}} plików",
|
||||
"Migration completed successfully!": "Migracja zakończona pomyślnie!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Twoje dane zostały przeniesione do nowej lokalizacji. Proszę zrestartować aplikację, aby zakończyć proces.",
|
||||
"Migration failed": "Migracja nie powiodła się",
|
||||
"Important Notice": "Ważne powiadomienie",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "To przeniesie wszystkie dane aplikacji do nowej lokalizacji. Upewnij się, że docelowy folder ma wystarczająco dużo wolnego miejsca.",
|
||||
"Restart App": "Zrestartuj aplikację",
|
||||
"Start Migration": "Rozpocznij migrację",
|
||||
"Advanced Settings": "Ustawienia zaawansowane",
|
||||
"File count: {{size}}": "Liczba plików: {{size}}"
|
||||
}
|
||||
|
||||
@@ -578,5 +578,27 @@
|
||||
"Single Page": "Página Única",
|
||||
"Auto Spread": "Espalhamento Automático",
|
||||
"Fit Page": "Ajustar Página",
|
||||
"Fit Width": "Ajustar Largura"
|
||||
"Fit Width": "Ajustar Largura",
|
||||
"Failed to select directory": "Falha ao selecionar diretório",
|
||||
"The new data directory must be different from the current one.": "O novo diretório de dados deve ser diferente do atual.",
|
||||
"Migration failed: {{error}}": "A migração falhou: {{error}}",
|
||||
"Change Data Location": "Alterar Localização dos Dados",
|
||||
"Current Data Location": "Localização Atual dos Dados",
|
||||
"Total size: {{size}}": "Tamanho total: {{size}}",
|
||||
"Calculating file info...": "Calculando informações do arquivo...",
|
||||
"New Data Location": "Nova Localização dos Dados",
|
||||
"Choose Different Folder": "Escolher Pasta Diferente",
|
||||
"Choose New Folder": "Escolher Nova Pasta",
|
||||
"Migrating data...": "Migrando dados...",
|
||||
"Copying: {{file}}": "Copiando: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} de {{total}} arquivos",
|
||||
"Migration completed successfully!": "Migração concluída com sucesso!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Seus dados foram movidos para a nova localização. Reinicie o aplicativo para concluir o processo.",
|
||||
"Migration failed": "Migração falhou",
|
||||
"Important Notice": "Aviso Importante",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Isso moverá todos os dados do seu aplicativo para a nova localização. Certifique-se de que o destino tenha espaço livre suficiente.",
|
||||
"Restart App": "Reiniciar Aplicativo",
|
||||
"Start Migration": "Iniciar Migração",
|
||||
"Advanced Settings": "Configurações Avançadas",
|
||||
"File count: {{size}}": "Contagem de arquivos: {{size}}"
|
||||
}
|
||||
|
||||
@@ -582,5 +582,27 @@
|
||||
"Single Page": "Одна страница",
|
||||
"Auto Spread": "Автоматическое растяжение",
|
||||
"Fit Page": "Подогнать страницу",
|
||||
"Fit Width": "Подогнать ширину"
|
||||
"Fit Width": "Подогнать ширину",
|
||||
"Failed to select directory": "Не удалось выбрать каталог",
|
||||
"The new data directory must be different from the current one.": "Новая директория данных должна отличаться от текущей.",
|
||||
"Migration failed: {{error}}": "Ошибка миграции: {{error}}",
|
||||
"Change Data Location": "Изменить расположение данных",
|
||||
"Current Data Location": "Текущее расположение данных",
|
||||
"Total size: {{size}}": "Общий размер: {{size}}",
|
||||
"Calculating file info...": "Вычисление информации о файле...",
|
||||
"New Data Location": "Новое расположение данных",
|
||||
"Choose Different Folder": "Выбрать другую папку",
|
||||
"Choose New Folder": "Выбрать новую папку",
|
||||
"Migrating data...": "Миграция данных...",
|
||||
"Copying: {{file}}": "Копирование: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} из {{total}} файлов",
|
||||
"Migration completed successfully!": "Миграция завершена успешно!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Ваши данные были перемещены в новое расположение. Пожалуйста, перезапустите приложение, чтобы завершить процесс.",
|
||||
"Migration failed": "Ошибка миграции",
|
||||
"Important Notice": "Важное уведомление",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Это переместит все ваши данные приложения в новое расположение. Убедитесь, что в целевом месте достаточно свободного места.",
|
||||
"Restart App": "Перезапустить приложение",
|
||||
"Start Migration": "Начать миграцию",
|
||||
"Advanced Settings": "Расширенные настройки",
|
||||
"File count: {{size}}": "Количество файлов: {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "එක් පිටුව",
|
||||
"Auto Spread": "ස්වයංක්රීය ව්යාප්තිය",
|
||||
"Fit Page": "පිටුවට ගැලපෙන ලෙස",
|
||||
"Fit Width": "පැතිකඩට ගැලපෙන ලෙස"
|
||||
"Fit Width": "පැතිකඩට ගැලපෙන ලෙස",
|
||||
"Failed to select directory": "ෆෝල්ඩරය තෝරා ගැනීමට අසමත්",
|
||||
"The new data directory must be different from the current one.": "නව දත්ත ෆෝල්ඩරය වර්තමාන ෆෝල්ඩරයෙන් වෙනස් විය යුතුය.",
|
||||
"Migration failed: {{error}}": "මැතිවරණය අසමත් විය: {{error}}",
|
||||
"Change Data Location": "දත්ත ස්ථානය වෙනස් කරන්න",
|
||||
"Current Data Location": "වර්තමාන දත්ත ස්ථානය",
|
||||
"Total size: {{size}}": "මුළු ප්රමාණය: {{size}}",
|
||||
"Calculating file info...": "ගොනු තොරතුරු ගණනය කරමින්...",
|
||||
"New Data Location": "නව දත්ත ස්ථානය",
|
||||
"Choose Different Folder": "වෙනත් ෆෝල්ඩරයක් තෝරන්න",
|
||||
"Choose New Folder": "නව ෆෝල්ඩරයක් තෝරන්න",
|
||||
"Migrating data...": "දත්ත මැතිවරණය කරමින්...",
|
||||
"Copying: {{file}}": "පිටපත් කරමින්: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}}/{{total}} ගොනු",
|
||||
"Migration completed successfully!": "මැතිවරණය සාර්ථකව නිමවිය!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "ඔබගේ දත්ත නව ස්ථානයට මාරු කර ඇත. ක්රියාවලිය සම්පූර්ණ කිරීමට කරුණාකර යෙදුම නැවත ආරම්භ කරන්න.",
|
||||
"Migration failed": "මැතිවරණය අසමත් විය",
|
||||
"Important Notice": "මහත් අවධානයක්",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "මෙය ඔබගේ යෙදුම් දත්ත සියල්ල නව ස්ථානයට මාරු කරනු ඇත. ගමන් මාර්ගය ප්රමාණවත් නිදහස් ස්ථානයක් ඇති බවට සහතික වන්න.",
|
||||
"Restart App": "යෙදුම නැවත ආරම්භ කරන්න",
|
||||
"Start Migration": "මැතිවරණය ආරම්භ කරන්න",
|
||||
"Advanced Settings": "උසස් සැකසුම්",
|
||||
"File count: {{size}}": "ගොනු ගණන: {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "ஒரு பக்கம்",
|
||||
"Auto Spread": "தானாக பரவல்",
|
||||
"Fit Page": "பக்கத்திற்கு பொருந்தும்",
|
||||
"Fit Width": "அகலத்திற்கு பொருந்தும்"
|
||||
"Fit Width": "அகலத்திற்கு பொருந்தும்",
|
||||
"Failed to select directory": "கோப்புறையைத் தேர்வுசெய்ய முடியவில்லை",
|
||||
"The new data directory must be different from the current one.": "புதிய தரவுக் கோப்புறை தற்போதையதைப் போலவே இருக்கக்கூடாது.",
|
||||
"Migration failed: {{error}}": "மொத்தமாக்கல் தோல்வியுற்றது: {{error}}",
|
||||
"Change Data Location": "தரவுப் இடத்தை மாற்றவும்",
|
||||
"Current Data Location": "தற்போதைய தரவுப் இடம்",
|
||||
"Total size: {{size}}": "மொத்த அளவு: {{size}}",
|
||||
"Calculating file info...": "கோப்பு தகவலை கணக்கிடுகிறது...",
|
||||
"New Data Location": "புதிய தரவுப் இடம்",
|
||||
"Choose Different Folder": "வேறுபட்ட கோப்புறையைத் தேர்ந்தெடுக்கவும்",
|
||||
"Choose New Folder": "புதிய கோப்புறையைத் தேர்ந்தெடுக்கவும்",
|
||||
"Migrating data...": "தரவை மாறுகிறது...",
|
||||
"Copying: {{file}}": "பகுப்பாய்வு: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}}/{{total}} கோப்புகள்",
|
||||
"Migration completed successfully!": "மொத்தமாக்கல் வெற்றிகரமாக முடிந்தது!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "உங்கள் தரவுகள் புதிய இடத்திற்கு மாறியுள்ளன. செயலியை மீண்டும் தொடங்கவும்.",
|
||||
"Migration failed": "மொத்தமாக்கல் தோல்வியுற்றது",
|
||||
"Important Notice": "முக்கிய அறிவிப்பு",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "இது உங்கள் செயலியின் அனைத்து தரவுகளையும் புதிய இடத்திற்கு நகர்த்தும். இலக்கு இடத்தில் போதுமான இலவச இடம் உள்ளதா என்பதை உறுதிப்படுத்தவும்.",
|
||||
"Restart App": "செயலியை மீண்டும் தொடங்கவும்",
|
||||
"Start Migration": "மொத்தமாக்கலை தொடங்கவும்",
|
||||
"Advanced Settings": "மேம்பட்ட அமைப்புகள்",
|
||||
"File count: {{size}}": "கோப்பு எண்ணிக்கை: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "หน้าเดียว",
|
||||
"Auto Spread": "การกระจายอัตโนมัติ",
|
||||
"Fit Page": "พอดีกับหน้า",
|
||||
"Fit Width": "พอดีกับความกว้าง"
|
||||
"Fit Width": "พอดีกับความกว้าง",
|
||||
"Failed to select directory": "ไม่สามารถเลือกไดเรกทอรีได้",
|
||||
"The new data directory must be different from the current one.": "ไดเรกทอรีข้อมูลใหม่จะต้องแตกต่างจากไดเรกทอรีปัจจุบัน",
|
||||
"Migration failed: {{error}}": "การย้ายข้อมูลล้มเหลว: {{error}}",
|
||||
"Change Data Location": "เปลี่ยนตำแหน่งข้อมูล",
|
||||
"Current Data Location": "ตำแหน่งข้อมูลปัจจุบัน",
|
||||
"Total size: {{size}}": "ขนาดรวม: {{size}}",
|
||||
"Calculating file info...": "กำลังคำนวณข้อมูลไฟล์...",
|
||||
"New Data Location": "ตำแหน่งข้อมูลใหม่",
|
||||
"Choose Different Folder": "เลือกโฟลเดอร์ที่แตกต่าง",
|
||||
"Choose New Folder": "เลือกโฟลเดอร์ใหม่",
|
||||
"Migrating data...": "กำลังย้ายข้อมูล...",
|
||||
"Copying: {{file}}": "กำลังคัดลอก: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} จาก {{total}} ไฟล์",
|
||||
"Migration completed successfully!": "การย้ายข้อมูลเสร็จสมบูรณ์!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "ข้อมูลของคุณได้ถูกย้ายไปยังตำแหน่งใหม่แล้ว กรุณารีสตาร์ทแอปพลิเคชันเพื่อทำให้กระบวนการเสร็จสมบูรณ์",
|
||||
"Migration failed": "การย้ายข้อมูลล้มเหลว",
|
||||
"Important Notice": "ประกาศสำคัญ",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "สิ่งนี้จะย้ายข้อมูลแอปทั้งหมดของคุณไปยังตำแหน่งใหม่ ตรวจสอบให้แน่ใจว่าตำแหน่งปลายทางมีพื้นที่ว่างเพียงพอ",
|
||||
"Restart App": "รีสตาร์ทแอป",
|
||||
"Start Migration": "เริ่มการย้ายข้อมูล",
|
||||
"Advanced Settings": "การตั้งค่าขั้นสูง",
|
||||
"File count: {{size}}": "จำนวนไฟล์: {{size}}"
|
||||
}
|
||||
|
||||
@@ -574,5 +574,27 @@
|
||||
"Single Page": "Tek Sayfa",
|
||||
"Auto Spread": "Otomatik Yayılma",
|
||||
"Fit Page": "Sayfaya Sığdır",
|
||||
"Fit Width": "Genişliğe Sığdır"
|
||||
"Fit Width": "Genişliğe Sığdır",
|
||||
"Failed to select directory": "Dizini seçme başarısız oldu",
|
||||
"The new data directory must be different from the current one.": "Yeni veri dizini mevcut olanla farklı olmalıdır.",
|
||||
"Migration failed: {{error}}": "Taşıma işlemi başarısız oldu: {{error}}",
|
||||
"Change Data Location": "Veri Konumunu Değiştir",
|
||||
"Current Data Location": "Mevcut Veri Konumu",
|
||||
"Total size: {{size}}": "Toplam boyut: {{size}}",
|
||||
"Calculating file info...": "Dosya bilgileri hesaplanıyor...",
|
||||
"New Data Location": "Yeni Veri Konumu",
|
||||
"Choose Different Folder": "Farklı Klasör Seç",
|
||||
"Choose New Folder": "Yeni Klasör Seç",
|
||||
"Migrating data...": "Veri taşınıyor...",
|
||||
"Copying: {{file}}": "Kopyalanıyor: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} / {{total}} dosya",
|
||||
"Migration completed successfully!": "Taşıma işlemi başarıyla tamamlandı!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Verileriniz yeni konuma taşındı. Lütfen işlemi tamamlamak için uygulamayı yeniden başlatın.",
|
||||
"Migration failed": "Taşıma işlemi başarısız oldu",
|
||||
"Important Notice": "Önemli Duyuru",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Bu, tüm uygulama verilerinizi yeni konuma taşıyacaktır. Hedefin yeterli boş alana sahip olduğundan emin olun.",
|
||||
"Restart App": "Uygulamayı Yeniden Başlat",
|
||||
"Start Migration": "Taşımayı Başlat",
|
||||
"Advanced Settings": "Gelişmiş Ayarlar",
|
||||
"File count: {{size}}": "Dosya sayısı: {{size}}"
|
||||
}
|
||||
|
||||
@@ -582,5 +582,27 @@
|
||||
"Single Page": "Одна сторінка",
|
||||
"Auto Spread": "Автоматичне розповсюдження",
|
||||
"Fit Page": "Підганяти під сторінку",
|
||||
"Fit Width": "Підганяти під ширину"
|
||||
"Fit Width": "Підганяти під ширину",
|
||||
"Failed to select directory": "Не вдалося вибрати каталог",
|
||||
"The new data directory must be different from the current one.": "Новий каталог даних повинен відрізнятися від поточного.",
|
||||
"Migration failed: {{error}}": "Переміщення не вдалося: {{error}}",
|
||||
"Change Data Location": "Змінити розташування даних",
|
||||
"Current Data Location": "Поточне розташування даних",
|
||||
"Total size: {{size}}": "Загальний розмір: {{size}}",
|
||||
"Calculating file info...": "Обчислення інформації про файл...",
|
||||
"New Data Location": "Нове розташування даних",
|
||||
"Choose Different Folder": "Вибрати іншу папку",
|
||||
"Choose New Folder": "Вибрати нову папку",
|
||||
"Migrating data...": "Переміщення даних...",
|
||||
"Copying: {{file}}": "Копіювання: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} з {{total}} файлів",
|
||||
"Migration completed successfully!": "Переміщення завершено успішно!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Ваші дані були переміщені до нового розташування. Будь ласка, перезапустіть програму, щоб завершити процес.",
|
||||
"Migration failed": "Переміщення не вдалося",
|
||||
"Important Notice": "Важливе повідомлення",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Це перемістить всі ваші дані програми до нового розташування. Переконайтеся, що в призначенні достатньо вільного місця.",
|
||||
"Restart App": "Перезапустити програму",
|
||||
"Start Migration": "Почати переміщення",
|
||||
"Advanced Settings": "Розширені налаштування",
|
||||
"File count: {{size}}": "Кількість файлів: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "Một trang",
|
||||
"Auto Spread": "Tự động trải rộng",
|
||||
"Fit Page": "Vừa trang",
|
||||
"Fit Width": "Vừa chiều rộng"
|
||||
"Fit Width": "Vừa chiều rộng",
|
||||
"Failed to select directory": "Không thể chọn thư mục",
|
||||
"The new data directory must be different from the current one.": "Thư mục dữ liệu mới phải khác với thư mục hiện tại.",
|
||||
"Migration failed: {{error}}": "Di chuyển không thành công: {{error}}",
|
||||
"Change Data Location": "Thay đổi vị trí dữ liệu",
|
||||
"Current Data Location": "Vị trí dữ liệu hiện tại",
|
||||
"Total size: {{size}}": "Tổng kích thước: {{size}}",
|
||||
"Calculating file info...": "Đang tính toán thông tin tệp...",
|
||||
"New Data Location": "Vị trí dữ liệu mới",
|
||||
"Choose Different Folder": "Chọn thư mục khác",
|
||||
"Choose New Folder": "Chọn thư mục mới",
|
||||
"Migrating data...": "Đang di chuyển dữ liệu...",
|
||||
"Copying: {{file}}": "Đang sao chép: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} của {{total}} tệp",
|
||||
"Migration completed successfully!": "Di chuyển hoàn tất thành công!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "Dữ liệu của bạn đã được chuyển đến vị trí mới. Vui lòng khởi động lại ứng dụng để hoàn tất quá trình.",
|
||||
"Migration failed": "Di chuyển không thành công",
|
||||
"Important Notice": "Thông báo quan trọng",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "Điều này sẽ di chuyển tất cả dữ liệu ứng dụng của bạn đến vị trí mới. Hãy chắc chắn rằng đích đến có đủ không gian trống.",
|
||||
"Restart App": "Khởi động lại ứng dụng",
|
||||
"Start Migration": "Bắt đầu di chuyển",
|
||||
"Advanced Settings": "Cài đặt nâng cao",
|
||||
"File count: {{size}}": "Số lượng tệp: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "单页",
|
||||
"Auto Spread": "自动展开",
|
||||
"Fit Page": "适应页面",
|
||||
"Fit Width": "适应宽度"
|
||||
"Fit Width": "适应宽度",
|
||||
"Failed to select directory": "选择目录失败",
|
||||
"The new data directory must be different from the current one.": "新的数据目录必须与当前目录不同。",
|
||||
"Migration failed: {{error}}": "迁移失败: {{error}}",
|
||||
"Change Data Location": "更改数据位置",
|
||||
"Current Data Location": "当前数据位置",
|
||||
"Total size: {{size}}": "总大小: {{size}}",
|
||||
"Calculating file info...": "正在计算文件信息...",
|
||||
"New Data Location": "新数据位置",
|
||||
"Choose Different Folder": "选择不同的文件夹",
|
||||
"Choose New Folder": "选择新文件夹",
|
||||
"Migrating data...": "正在迁移数据...",
|
||||
"Copying: {{file}}": "正在复制: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} / {{total}} 个文件",
|
||||
"Migration completed successfully!": "迁移成功完成!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "您的数据已移动到新位置。请重新启动应用程序以完成此过程。",
|
||||
"Migration failed": "迁移失败",
|
||||
"Important Notice": "重要通知",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "这将把您所有的应用数据移动到新位置。请确保目标位置有足够的可用空间。",
|
||||
"Restart App": "重启应用",
|
||||
"Start Migration": "开始迁移",
|
||||
"Advanced Settings": "高级设置",
|
||||
"File count: {{size}}": "文件数量: {{size}}"
|
||||
}
|
||||
|
||||
@@ -570,5 +570,27 @@
|
||||
"Single Page": "單頁",
|
||||
"Auto Spread": "自動展開",
|
||||
"Fit Page": "適應頁面",
|
||||
"Fit Width": "適應寬度"
|
||||
"Fit Width": "適應寬度",
|
||||
"Failed to select directory": "選擇目錄失敗",
|
||||
"The new data directory must be different from the current one.": "新的數據目錄必須與當前目錄不同。",
|
||||
"Migration failed: {{error}}": "遷移失敗: {{error}}",
|
||||
"Change Data Location": "更改數據位置",
|
||||
"Current Data Location": "當前數據位置",
|
||||
"Total size: {{size}}": "總大小: {{size}}",
|
||||
"Calculating file info...": "正在計算文件信息...",
|
||||
"New Data Location": "新的數據位置",
|
||||
"Choose Different Folder": "選擇不同的文件夾",
|
||||
"Choose New Folder": "選擇新文件夾",
|
||||
"Migrating data...": "正在遷移數據...",
|
||||
"Copying: {{file}}": "正在複製: {{file}}",
|
||||
"{{current}} of {{total}} files": "{{current}} / {{total}} 個文件",
|
||||
"Migration completed successfully!": "遷移成功完成!",
|
||||
"Your data has been moved to the new location. Please restart the application to complete the process.": "您的數據已移動到新位置。請重新啟動應用程序以完成此過程。",
|
||||
"Migration failed": "遷移失敗",
|
||||
"Important Notice": "重要通知",
|
||||
"This will move all your app data to the new location. Make sure the destination has enough free space.": "這將把您所有的應用數據移動到新位置。請確保目標位置有足夠的可用空間。",
|
||||
"Restart App": "重新啟動應用",
|
||||
"Start Migration": "開始遷移",
|
||||
"Advanced Settings": "高級設置",
|
||||
"File count: {{size}}": "文件數量: {{size}}"
|
||||
}
|
||||
|
||||
@@ -61,6 +61,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [
|
||||
{
|
||||
"path": "**/Readest"
|
||||
},
|
||||
{
|
||||
"path": "**/Readest/**/*"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"identifier": "http:default",
|
||||
"allow": [
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"$APPDATA/**/*",
|
||||
"$APPCACHE/**/*",
|
||||
"$TEMP/**/*",
|
||||
"**/Readest/**/*",
|
||||
"/private/var/mobile/Containers/Data/Application/**/*"
|
||||
],
|
||||
"deny": []
|
||||
|
||||
@@ -290,7 +290,7 @@ const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
groupContextMenuHandler(item as BooksGroup);
|
||||
}
|
||||
}, 100),
|
||||
[itemSelected],
|
||||
[itemSelected, settings.localBooksDir],
|
||||
);
|
||||
|
||||
const { pressing, handlers } = useLongPress(
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
RiFolderOpenLine,
|
||||
RiCheckboxCircleFill,
|
||||
RiErrorWarningFill,
|
||||
RiLoader2Line,
|
||||
} from 'react-icons/ri';
|
||||
import { join } from '@tauri-apps/api/path';
|
||||
import { relaunch } from '@tauri-apps/plugin-process';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { revealItemInDir } from '@tauri-apps/plugin-opener';
|
||||
import { DATA_SUBDIR } from '@/services/constants';
|
||||
import { FileItem } from '@/types/system';
|
||||
import { getDirPath } from '@/utils/path';
|
||||
import { getOSPlatform } from '@/utils/misc';
|
||||
import { FILE_REVEAL_LABELS, FILE_REVEAL_PLATFORMS } from '@/utils/os';
|
||||
import Dialog from '@/components/Dialog';
|
||||
import { formatBytes } from '@/utils/book';
|
||||
|
||||
export const setMigrateDataDirDialogVisible = (visible: boolean) => {
|
||||
const dialog = document.getElementById('migrate_data_dir_window');
|
||||
if (dialog) {
|
||||
const event = new CustomEvent('setDialogVisibility', {
|
||||
detail: { visible },
|
||||
});
|
||||
dialog.dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
type MigrationStatus = 'idle' | 'selecting' | 'migrating' | 'completed' | 'error';
|
||||
|
||||
interface MigrationProgress {
|
||||
current: number;
|
||||
total: number;
|
||||
currentFile?: string;
|
||||
}
|
||||
|
||||
export const MigrateDataWindow = () => {
|
||||
const _ = useTranslation();
|
||||
const { appService, envConfig } = useEnv();
|
||||
const { settings, setSettings, saveSettings } = useSettingsStore();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [currentDataDir, setCurrentDataDir] = useState('');
|
||||
const [newDataDir, setNewDataDir] = useState('');
|
||||
const [migrationStatus, setMigrationStatus] = useState<MigrationStatus>('idle');
|
||||
const [migrationProgress, setMigrationProgress] = useState<MigrationProgress>({
|
||||
current: 0,
|
||||
total: 0,
|
||||
});
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const [filesToMigrate, setFilesToMigrate] = useState<FileItem[]>([]);
|
||||
const [currentDirFileCount, setCurrentDirFileCount] = useState('');
|
||||
const [currentDirFileSize, setCurrentDirFileSize] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleCustomEvent = (event: CustomEvent) => {
|
||||
setIsOpen(event.detail.visible);
|
||||
if (event.detail.visible) {
|
||||
loadCurrentDataDir();
|
||||
}
|
||||
};
|
||||
|
||||
const el = document.getElementById('migrate_data_dir_window');
|
||||
if (el) {
|
||||
el.addEventListener('setDialogVisibility', handleCustomEvent as EventListener);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (el) {
|
||||
el.removeEventListener('setDialogVisibility', handleCustomEvent as EventListener);
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadCurrentDataDir = async () => {
|
||||
try {
|
||||
if (!appService) return;
|
||||
|
||||
const dataDir = await appService.resolveFilePath('', 'Data');
|
||||
setCurrentDataDir(dataDir);
|
||||
const files = await appService.readDirectory(dataDir, 'None');
|
||||
setFilesToMigrate(files);
|
||||
setCurrentDirFileCount(files.length.toLocaleString());
|
||||
setCurrentDirFileSize(files.reduce((acc, file) => acc + file.size, 0));
|
||||
} catch (error) {
|
||||
console.error('Error loading current data directory:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectNewDir = async () => {
|
||||
setMigrationStatus('selecting');
|
||||
setErrorMessage('');
|
||||
|
||||
try {
|
||||
const selectedDir = await appService?.selectDirectory?.('write');
|
||||
if (selectedDir) {
|
||||
const newDataDir = await join(selectedDir, DATA_SUBDIR);
|
||||
await appService?.createDir(newDataDir, 'None', true);
|
||||
setNewDataDir(newDataDir);
|
||||
setMigrationStatus('idle');
|
||||
} else {
|
||||
setMigrationStatus('idle');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error selecting directory:', error);
|
||||
setErrorMessage(_('Failed to select directory'));
|
||||
setMigrationStatus('error');
|
||||
}
|
||||
};
|
||||
|
||||
const handleStartMigration = async () => {
|
||||
if (!appService || !currentDataDir || !newDataDir || !filesToMigrate.length) return;
|
||||
|
||||
setMigrationStatus('migrating');
|
||||
setErrorMessage('');
|
||||
setMigrationProgress({ current: 0, total: 0 });
|
||||
|
||||
try {
|
||||
if (newDataDir === currentDataDir) {
|
||||
throw new Error(_('The new data directory must be different from the current one.'));
|
||||
}
|
||||
|
||||
// Copy all files to new location
|
||||
for (let i = 0; i < filesToMigrate.length; i++) {
|
||||
const file = filesToMigrate[i]!;
|
||||
setMigrationProgress({
|
||||
current: i + 1,
|
||||
total: filesToMigrate.length,
|
||||
currentFile: file.path,
|
||||
});
|
||||
|
||||
const srcPath = await join(currentDataDir, file.path);
|
||||
const destPath = await join(newDataDir, file.path);
|
||||
await appService.copyFile(srcPath, destPath, 'None');
|
||||
}
|
||||
|
||||
// Verify all files copied
|
||||
const filesMigrated = await appService.readDirectory(newDataDir, 'None');
|
||||
for (const file of filesToMigrate) {
|
||||
if (!filesMigrated.find((f) => f.path === file.path && f.size === file.size)) {
|
||||
throw new Error(`File ${file.path} failed to copy.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old data directory
|
||||
await appService.deleteDir(currentDataDir, 'None', true);
|
||||
|
||||
// Update settings for new data directory
|
||||
const customRootDir = getDirPath(newDataDir);
|
||||
await appService.setCustomRootDir(customRootDir);
|
||||
settings.customRootDir = customRootDir;
|
||||
settings.localBooksDir = await appService.resolveFilePath('', 'Books');
|
||||
setSettings({ ...settings });
|
||||
await saveSettings(envConfig, settings);
|
||||
|
||||
// Finalize migration
|
||||
setMigrationStatus('completed');
|
||||
setCurrentDataDir(newDataDir);
|
||||
setFilesToMigrate([]);
|
||||
setCurrentDirFileCount('');
|
||||
setCurrentDirFileSize(0);
|
||||
loadCurrentDataDir();
|
||||
} catch (error) {
|
||||
console.error('Error migrating data:', error);
|
||||
setErrorMessage(_('Migration failed: {{error}}', { error: error || 'Unknown error' }));
|
||||
setMigrationStatus('error');
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (migrationStatus === 'migrating') {
|
||||
return;
|
||||
}
|
||||
setIsOpen(false);
|
||||
setNewDataDir('');
|
||||
setMigrationStatus('idle');
|
||||
setErrorMessage('');
|
||||
setMigrationProgress({ current: 0, total: 0 });
|
||||
};
|
||||
|
||||
const handleRestartApp = () => {
|
||||
relaunch();
|
||||
};
|
||||
|
||||
const handleRevealDir = (dataDir: string) => {
|
||||
if (dataDir) {
|
||||
revealItemInDir(dataDir);
|
||||
}
|
||||
};
|
||||
|
||||
const progressPercentage =
|
||||
migrationProgress.total > 0
|
||||
? Math.round((migrationProgress.current / migrationProgress.total) * 100)
|
||||
: 0;
|
||||
|
||||
const canStartMigration =
|
||||
newDataDir && newDataDir !== currentDataDir && migrationStatus === 'idle';
|
||||
|
||||
const osPlatform = getOSPlatform();
|
||||
const fileRevealLabel =
|
||||
FILE_REVEAL_LABELS[osPlatform as FILE_REVEAL_PLATFORMS] || FILE_REVEAL_LABELS.default;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
id='migrate_data_dir_window'
|
||||
isOpen={isOpen}
|
||||
title={_('Change Data Location')}
|
||||
onClose={handleClose}
|
||||
boxClassName='sm:!w-[520px] sm:!max-w-screen-sm sm:h-auto'
|
||||
>
|
||||
{isOpen && (
|
||||
<div className='migrate-data-dir-content flex flex-col gap-6 px-6 py-4'>
|
||||
{/* Current Data Directory */}
|
||||
<div className='space-y-2'>
|
||||
<h3 className='text-base-content text-sm font-semibold'>
|
||||
{_('Current Data Location')}
|
||||
</h3>
|
||||
<button
|
||||
title={_(fileRevealLabel)}
|
||||
className='bg-base-200 flex w-full items-center gap-2 rounded-lg p-3'
|
||||
onClick={() => handleRevealDir(currentDataDir)}
|
||||
>
|
||||
<RiFolderOpenLine className='text-base-content/70 h-4 w-4 flex-shrink-0' />
|
||||
<span className='text-base-content/80 break-all text-start font-mono text-sm'>
|
||||
{currentDataDir || _('Loading...')}
|
||||
</span>
|
||||
</button>
|
||||
{currentDirFileCount ? (
|
||||
<div className='flex space-x-4'>
|
||||
<p className='text-base-content/60 text-xs'>
|
||||
{_('File count: {{size}}', { size: currentDirFileCount })}
|
||||
</p>
|
||||
<p className='text-base-content/60 text-xs'>
|
||||
{_('Total size: {{size}}', { size: formatBytes(currentDirFileSize) })}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<p className='text-base-content/60 text-xs'>{_('Calculating file info...')}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* New Data Directory Selection */}
|
||||
<div className='space-y-3'>
|
||||
<h3 className='text-base-content text-sm font-semibold'>{_('New Data Location')}</h3>
|
||||
|
||||
{newDataDir && (
|
||||
<button
|
||||
title={_(fileRevealLabel)}
|
||||
className='bg-primary/10 border-primary/20 flex w-full items-center gap-2 rounded-lg border p-3'
|
||||
onClick={() => handleRevealDir(newDataDir)}
|
||||
>
|
||||
<RiFolderOpenLine className='text-primary h-4 w-4 flex-shrink-0' />
|
||||
<span className='text-primary break-all text-start font-mono text-sm'>
|
||||
{newDataDir}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
className='btn btn-outline btn-sm w-full'
|
||||
onClick={handleSelectNewDir}
|
||||
disabled={migrationStatus === 'migrating' || migrationStatus === 'selecting'}
|
||||
>
|
||||
{migrationStatus === 'selecting' && (
|
||||
<RiLoader2Line className='h-4 w-4 animate-spin' />
|
||||
)}
|
||||
{newDataDir ? _('Choose Different Folder') : _('Choose New Folder')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Migration Progress */}
|
||||
{migrationStatus === 'migrating' && (
|
||||
<div className='space-y-3'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<RiLoader2Line className='text-primary h-4 w-4 animate-spin' />
|
||||
<span className='text-base-content text-sm font-medium'>
|
||||
{_('Migrating data...')}
|
||||
</span>
|
||||
<span className='text-base-content/70 text-sm'>{progressPercentage}%</span>
|
||||
</div>
|
||||
|
||||
<div className='bg-base-200 h-2 w-full rounded-full'>
|
||||
<div
|
||||
className='bg-primary h-2 rounded-full transition-all duration-300'
|
||||
style={{ width: `${progressPercentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{migrationProgress.currentFile && (
|
||||
<p
|
||||
className='text-base-content/60 overflow-hidden font-mono text-xs'
|
||||
style={{
|
||||
direction: 'rtl',
|
||||
textAlign: 'left',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{_('Copying: {{file}}', { file: migrationProgress.currentFile })}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<p className='text-base-content/60 text-xs'>
|
||||
{_('{{current}} of {{total}} files', {
|
||||
current: migrationProgress.current.toLocaleString(),
|
||||
total: migrationProgress.total.toLocaleString(),
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Success State */}
|
||||
{migrationStatus === 'completed' && (
|
||||
<div className='space-y-3'>
|
||||
<div className='text-success flex items-center gap-2'>
|
||||
<RiCheckboxCircleFill className='h-5 w-5' />
|
||||
<span className='font-medium'>{_('Migration completed successfully!')}</span>
|
||||
</div>
|
||||
<div className='bg-success/10 border-success/20 rounded-lg border p-3'>
|
||||
<p className='text-success/80 text-sm'>
|
||||
{_(
|
||||
'Your data has been moved to the new location. Please restart the application to complete the process.',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Error State */}
|
||||
{migrationStatus === 'error' && errorMessage && (
|
||||
<div className='space-y-2'>
|
||||
<div className='text-error flex items-center gap-2'>
|
||||
<RiErrorWarningFill className='h-5 w-5' />
|
||||
<span className='font-medium'>{_('Migration failed')}</span>
|
||||
</div>
|
||||
<div className='bg-error/10 border-error/20 rounded-lg border p-3'>
|
||||
<p className='text-error/80 text-sm'>{errorMessage}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Warning */}
|
||||
{canStartMigration && (
|
||||
<div className='bg-warning/10 border-warning/20 rounded-lg border p-3'>
|
||||
<div className='flex items-start gap-2'>
|
||||
<RiErrorWarningFill className='text-warning mt-0.5 h-4 w-4 flex-shrink-0' />
|
||||
<div className='space-y-1'>
|
||||
<p className='text-base-content text-sm font-medium'>{_('Important Notice')}</p>
|
||||
<p className='text-base-content/80 text-sm'>
|
||||
{_(
|
||||
'This will move all your app data to the new location. Make sure the destination has enough free space.',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className='flex gap-3 pt-2'>
|
||||
{migrationStatus === 'completed' ? (
|
||||
<>
|
||||
<button className='btn btn-outline flex-1' onClick={handleClose}>
|
||||
{_('Close')}
|
||||
</button>
|
||||
<button className='btn btn-primary flex-1' onClick={handleRestartApp}>
|
||||
{_('Restart App')}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
className='btn btn-outline flex-1'
|
||||
onClick={handleClose}
|
||||
disabled={migrationStatus === 'migrating'}
|
||||
>
|
||||
{_('Cancel')}
|
||||
</button>
|
||||
<button
|
||||
className='btn btn-primary flex-1'
|
||||
onClick={handleStartMigration}
|
||||
disabled={!canStartMigration || migrationStatus !== 'idle'}
|
||||
>
|
||||
{migrationStatus === 'migrating' && (
|
||||
<RiLoader2Line className='h-4 w-4 animate-spin' />
|
||||
)}
|
||||
{_('Start Migration')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -6,7 +6,6 @@ import { PiUserCircleCheck } from 'react-icons/pi';
|
||||
import { TbSunMoon } from 'react-icons/tb';
|
||||
import { BiMoon, BiSun } from 'react-icons/bi';
|
||||
|
||||
import { setAboutDialogVisible } from '@/components/AboutWindow';
|
||||
import { isTauriAppPlatform, isWebAppPlatform } from '@/services/environment';
|
||||
import { DOWNLOAD_READEST_URL } from '@/services/constants';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
@@ -19,6 +18,8 @@ import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
import { navigateToLogin, navigateToProfile } from '@/utils/nav';
|
||||
import { tauriHandleSetAlwaysOnTop, tauriHandleToggleFullScreen } from '@/utils/window';
|
||||
import { optInTelemetry, optOutTelemetry } from '@/utils/telemetry';
|
||||
import { setAboutDialogVisible } from '@/components/AboutWindow';
|
||||
import { setMigrateDataDirDialogVisible } from '@/app/library/components/MigrateDataWindow';
|
||||
import UserAvatar from '@/components/UserAvatar';
|
||||
import MenuItem from '@/components/MenuItem';
|
||||
import Quota from '@/components/Quota';
|
||||
@@ -162,6 +163,11 @@ const SettingsMenu: React.FC<SettingsMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
setIsDropdownOpen?.(false);
|
||||
};
|
||||
|
||||
const handleSetRootDir = () => {
|
||||
setMigrateDataDirDialogVisible(true);
|
||||
setIsDropdownOpen?.(false);
|
||||
};
|
||||
|
||||
const avatarUrl = user?.user_metadata?.['picture'] || user?.user_metadata?.['avatar_url'];
|
||||
const userFullName = user?.user_metadata?.['full_name'];
|
||||
const userDisplayName = userFullName ? userFullName.split(' ')[0] : null;
|
||||
@@ -262,6 +268,16 @@ const SettingsMenu: React.FC<SettingsMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
Icon={themeMode === 'dark' ? BiMoon : themeMode === 'light' ? BiSun : TbSunMoon}
|
||||
onClick={cycleThemeMode}
|
||||
/>
|
||||
{appService?.isDesktopApp && !appService?.isPortableApp && (
|
||||
<>
|
||||
<hr aria-hidden='true' className='border-base-200 my-1' />
|
||||
<MenuItem label={_('Advanced Settings')}>
|
||||
<ul className='flex flex-col'>
|
||||
<MenuItem label={_('Change Data Location')} noIcon onClick={handleSetRootDir} />
|
||||
</ul>
|
||||
</MenuItem>
|
||||
</>
|
||||
)}
|
||||
<hr aria-hidden='true' className='border-base-200 my-1' />
|
||||
{user && userPlan === 'free' && !appService?.isIOSApp && (
|
||||
<MenuItem label={_('Upgrade to Readest Premium')} onClick={handleUpgrade} />
|
||||
|
||||
@@ -43,10 +43,11 @@ import {
|
||||
tauriQuitApp,
|
||||
} from '@/utils/window';
|
||||
|
||||
import { AboutWindow } from '@/components/AboutWindow';
|
||||
import { UpdaterWindow } from '@/components/UpdaterWindow';
|
||||
import { BookMetadata } from '@/libs/document';
|
||||
import { AboutWindow } from '@/components/AboutWindow';
|
||||
import { BookDetailModal } from '@/components/metadata';
|
||||
import { UpdaterWindow } from '@/components/UpdaterWindow';
|
||||
import { MigrateDataWindow } from './components/MigrateDataWindow';
|
||||
import { Toast } from '@/components/Toast';
|
||||
import Spinner from '@/components/Spinner';
|
||||
import LibraryHeader from './components/LibraryHeader';
|
||||
@@ -729,6 +730,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
||||
)}
|
||||
<AboutWindow />
|
||||
<UpdaterWindow />
|
||||
<MigrateDataWindow />
|
||||
<Toast />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useTranslation } from '@/hooks/useTranslation';
|
||||
import {
|
||||
formatAuthors,
|
||||
formatDate,
|
||||
formatFileSize,
|
||||
formatBytes,
|
||||
formatLanguage,
|
||||
formatPublisher,
|
||||
formatTitle,
|
||||
@@ -158,9 +158,7 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
</div>
|
||||
<div className='overflow-hidden'>
|
||||
<span className='font-bold'>{_('File Size')}</span>
|
||||
<p className='text-neutral-content text-sm'>
|
||||
{formatFileSize(fileSize) || _('Unknown')}
|
||||
</p>
|
||||
<p className='text-neutral-content text-sm'>{formatBytes(fileSize) || _('Unknown')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { SystemSettings } from '@/types/settings';
|
||||
import { AppPlatform, AppService, OsPlatform, ResolvedPath } from '@/types/system';
|
||||
import {
|
||||
AppPlatform,
|
||||
AppService,
|
||||
FileItem,
|
||||
OsPlatform,
|
||||
ResolvedPath,
|
||||
SelectDirectoryMode,
|
||||
} from '@/types/system';
|
||||
import { FileSystem, BaseDir, DeleteAction } from '@/types/system';
|
||||
import {
|
||||
Book,
|
||||
@@ -68,6 +75,7 @@ export abstract class BaseAppService implements AppService {
|
||||
isIOSApp = false;
|
||||
isMobileApp = false;
|
||||
isPortableApp = false;
|
||||
isDesktopApp = false;
|
||||
hasTrafficLight = false;
|
||||
hasWindow = false;
|
||||
hasWindowBar = false;
|
||||
@@ -83,10 +91,12 @@ export abstract class BaseAppService implements AppService {
|
||||
protected abstract fs: FileSystem;
|
||||
protected abstract resolvePath(fp: string, base: BaseDir): ResolvedPath;
|
||||
|
||||
abstract selectDirectory(): Promise<string>;
|
||||
abstract init(): Promise<void>;
|
||||
abstract setCustomRootDir(customRootDir: string): Promise<void>;
|
||||
abstract selectDirectory(mode: SelectDirectoryMode): Promise<string>;
|
||||
abstract selectFiles(name: string, extensions: string[]): Promise<string[]>;
|
||||
|
||||
async init() {
|
||||
async prepareBooksDir() {
|
||||
this.localBooksDir = await this.fs.getPrefix('Books');
|
||||
}
|
||||
|
||||
@@ -94,9 +104,29 @@ export abstract class BaseAppService implements AppService {
|
||||
return await this.fs.openFile(path, base);
|
||||
}
|
||||
|
||||
async copyFile(srcPath: string, dstPath: string, base: BaseDir): Promise<void> {
|
||||
return await this.fs.copyFile(srcPath, dstPath, base);
|
||||
}
|
||||
|
||||
async createDir(path: string, base: BaseDir, recursive: boolean = true): Promise<void> {
|
||||
return await this.fs.createDir(path, base, recursive);
|
||||
}
|
||||
|
||||
async deleteFile(path: string, base: BaseDir): Promise<void> {
|
||||
return await this.fs.removeFile(path, base);
|
||||
}
|
||||
|
||||
async deleteDir(path: string, base: BaseDir, recursive: boolean = true): Promise<void> {
|
||||
return await this.fs.removeDir(path, base, recursive);
|
||||
}
|
||||
|
||||
async resolveFilePath(path: string, base: BaseDir): Promise<string> {
|
||||
const prefix = await this.fs.getPrefix(base);
|
||||
return `${prefix}/${path}`;
|
||||
return path ? `${prefix}/${path}` : prefix;
|
||||
}
|
||||
|
||||
async readDirectory(path: string, base: BaseDir): Promise<FileItem[]> {
|
||||
return await this.fs.readDir(path, base);
|
||||
}
|
||||
|
||||
getCoverImageUrl = (book: Book): string => {
|
||||
|
||||
@@ -15,10 +15,10 @@ import { UserStorageQuota, UserDailyTranslationQuota } from '@/types/user';
|
||||
import { getDefaultMaxBlockSize, getDefaultMaxInlineSize } from '@/utils/config';
|
||||
import { stubTranslation as _ } from '@/utils/misc';
|
||||
|
||||
export const LOCAL_BOOKS_SUBDIR = 'Readest/Books';
|
||||
export const CLOUD_BOOKS_SUBDIR = 'Readest/Books';
|
||||
export const LOCAL_FONTS_SUBDIR = 'Readest/Fonts';
|
||||
export const LOCAL_DATA_SUBDIR = 'Readest/Data';
|
||||
export const DATA_SUBDIR = 'Readest';
|
||||
export const LOCAL_BOOKS_SUBDIR = `${DATA_SUBDIR}/Books`;
|
||||
export const CLOUD_BOOKS_SUBDIR = `${DATA_SUBDIR}/Books`;
|
||||
export const LOCAL_FONTS_SUBDIR = `${DATA_SUBDIR}/Fonts`;
|
||||
|
||||
export const SETTINGS_FILENAME = 'settings.json';
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
readDir,
|
||||
remove,
|
||||
copyFile,
|
||||
stat,
|
||||
BaseDirectory,
|
||||
WriteFileOptions,
|
||||
DirEntry,
|
||||
} from '@tauri-apps/plugin-fs';
|
||||
import { invoke, convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { open as openDialog } from '@tauri-apps/plugin-dialog';
|
||||
@@ -24,7 +26,7 @@ import {
|
||||
} from '@tauri-apps/api/path';
|
||||
import { type as osType } from '@tauri-apps/plugin-os';
|
||||
|
||||
import { FileSystem, BaseDir, AppPlatform, ResolvedPath } from '@/types/system';
|
||||
import { FileSystem, BaseDir, AppPlatform, ResolvedPath, FileItem } from '@/types/system';
|
||||
import { getOSPlatform, isContentURI, isValidURL } from '@/utils/misc';
|
||||
import { getDirPath, getFilename } from '@/utils/path';
|
||||
import { NativeFile, RemoteFile } from '@/utils/file';
|
||||
@@ -32,8 +34,8 @@ import { copyURIToPath } from '@/utils/bridge';
|
||||
|
||||
import { BaseAppService } from './appService';
|
||||
import {
|
||||
DATA_SUBDIR,
|
||||
LOCAL_BOOKS_SUBDIR,
|
||||
LOCAL_DATA_SUBDIR,
|
||||
LOCAL_FONTS_SUBDIR,
|
||||
SETTINGS_FILENAME,
|
||||
} from './constants';
|
||||
@@ -67,8 +69,10 @@ const getPathResolver = ({
|
||||
const isCustomBaseDir = Boolean(customRootDir);
|
||||
const getCustomBasePrefixSync = isCustomBaseDir
|
||||
? (baseDir: BaseDir) => {
|
||||
return () =>
|
||||
`${customRootDir}/${['Settings', 'Data', 'Books', 'Fonts'].includes(baseDir) ? '' : baseDir}`;
|
||||
return () => {
|
||||
const leafDir = ['Settings', 'Data', 'Books', 'Fonts'].includes(baseDir) ? '' : baseDir;
|
||||
return leafDir ? `${customRootDir}/${leafDir}` : customRootDir!;
|
||||
};
|
||||
}
|
||||
: undefined;
|
||||
|
||||
@@ -84,7 +88,7 @@ const getPathResolver = ({
|
||||
return {
|
||||
baseDir: isPortable ? 0 : BaseDirectory.AppConfig,
|
||||
basePrefix: isPortable && execDir ? async () => execDir : appConfigDir,
|
||||
fp: isPortable && execDir ? `${execDir}/${path}` : path,
|
||||
fp: isPortable && execDir ? `${execDir}${path ? `/${path}` : ''}` : path,
|
||||
base,
|
||||
};
|
||||
case 'Cache':
|
||||
@@ -98,7 +102,7 @@ const getPathResolver = ({
|
||||
return {
|
||||
baseDir: isCustomBaseDir ? 0 : BaseDirectory.AppLog,
|
||||
basePrefix: customBasePrefix ?? appLogDir,
|
||||
fp: customBasePrefixSync ? `${customBasePrefixSync()}/${path}` : path,
|
||||
fp: customBasePrefixSync ? `${customBasePrefixSync()}${path ? `/${path}` : ''}` : path,
|
||||
base,
|
||||
};
|
||||
case 'Data':
|
||||
@@ -106,8 +110,8 @@ const getPathResolver = ({
|
||||
baseDir: customBaseDir ?? BaseDirectory.AppData,
|
||||
basePrefix: customBasePrefix ?? appDataDir,
|
||||
fp: customBasePrefixSync
|
||||
? `${customBasePrefixSync()}/${LOCAL_DATA_SUBDIR}/${path}`
|
||||
: `${LOCAL_DATA_SUBDIR}/${path}`,
|
||||
? `${customBasePrefixSync()}/${DATA_SUBDIR}${path ? `/${path}` : ''}`
|
||||
: `${DATA_SUBDIR}${path ? `/${path}` : ''}`,
|
||||
base,
|
||||
};
|
||||
case 'Books':
|
||||
@@ -115,8 +119,8 @@ const getPathResolver = ({
|
||||
baseDir: customBaseDir ?? BaseDirectory.AppData,
|
||||
basePrefix: customBasePrefix || appDataDir,
|
||||
fp: customBasePrefixSync
|
||||
? `${customBasePrefixSync()}/${LOCAL_BOOKS_SUBDIR}/${path}`
|
||||
: `${LOCAL_BOOKS_SUBDIR}/${path}`,
|
||||
? `${customBasePrefixSync()}/${LOCAL_BOOKS_SUBDIR}${path ? `/${path}` : ''}`
|
||||
: `${LOCAL_BOOKS_SUBDIR}${path ? `/${path}` : ''}`,
|
||||
base,
|
||||
};
|
||||
case 'Fonts':
|
||||
@@ -124,8 +128,8 @@ const getPathResolver = ({
|
||||
baseDir: customBaseDir ?? BaseDirectory.AppData,
|
||||
basePrefix: customBasePrefix || appDataDir,
|
||||
fp: customBasePrefixSync
|
||||
? `${customBasePrefixSync()}/${LOCAL_FONTS_SUBDIR}/${path}`
|
||||
: `${LOCAL_FONTS_SUBDIR}/${path}`,
|
||||
? `${customBasePrefixSync()}/${LOCAL_FONTS_SUBDIR}${path ? `/${path}` : ''}`
|
||||
: `${LOCAL_FONTS_SUBDIR}${path ? `/${path}` : ''}`,
|
||||
base,
|
||||
};
|
||||
case 'None':
|
||||
@@ -152,7 +156,8 @@ export const nativeFileSystem: FileSystem = {
|
||||
|
||||
async getPrefix(base: BaseDir) {
|
||||
const { basePrefix, fp, baseDir } = this.resolvePath('', base);
|
||||
const basePath = await basePrefix();
|
||||
let basePath = await basePrefix();
|
||||
basePath = basePath.replace(/\/+$/, '');
|
||||
return fp ? (baseDir === 0 ? fp : await join(basePath, fp)) : basePath;
|
||||
},
|
||||
getURL(path: string) {
|
||||
@@ -200,6 +205,9 @@ export const nativeFileSystem: FileSystem = {
|
||||
}
|
||||
},
|
||||
async copyFile(srcPath: string, dstPath: string, base: BaseDir) {
|
||||
if (!(await this.exists(getDirPath(dstPath), base))) {
|
||||
await this.createDir(getDirPath(dstPath), base, true);
|
||||
}
|
||||
if (isContentURI(srcPath)) {
|
||||
const prefix = await this.getPrefix(base);
|
||||
if (!prefix) {
|
||||
@@ -264,13 +272,37 @@ export const nativeFileSystem: FileSystem = {
|
||||
async readDir(path: string, base: BaseDir) {
|
||||
const { fp, baseDir } = this.resolvePath(path, base);
|
||||
|
||||
const list = await readDir(fp, baseDir ? { baseDir } : undefined);
|
||||
return list.map((entity) => {
|
||||
return {
|
||||
path: entity.name,
|
||||
isDir: entity.isDirectory,
|
||||
};
|
||||
});
|
||||
const entries = await readDir(fp, baseDir ? { baseDir } : undefined);
|
||||
const fileList: FileItem[] = [];
|
||||
const readDirRecursively = async (
|
||||
parent: string,
|
||||
relative: string,
|
||||
entries: DirEntry[],
|
||||
fileList: FileItem[],
|
||||
) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory) {
|
||||
const dir = await join(parent, entry.name);
|
||||
const relativeDir = relative ? await join(relative, entry.name) : entry.name;
|
||||
await readDirRecursively(
|
||||
dir,
|
||||
relativeDir,
|
||||
await readDir(dir, baseDir ? { baseDir } : undefined),
|
||||
fileList,
|
||||
);
|
||||
} else {
|
||||
const filePath = await join(parent, entry.name);
|
||||
const relativePath = relative ? await join(relative, entry.name) : entry.name;
|
||||
const fileInfo = await stat(filePath, baseDir ? { baseDir } : undefined);
|
||||
fileList.push({
|
||||
path: relativePath,
|
||||
size: fileInfo.size,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
await readDirRecursively(path, '', entries, fileList);
|
||||
return fileList;
|
||||
},
|
||||
async exists(path: string, base: BaseDir) {
|
||||
const { fp, baseDir } = this.resolvePath(path, base);
|
||||
@@ -294,6 +326,7 @@ export class NativeAppService extends BaseAppService {
|
||||
override isMacOSApp = OS_TYPE === 'macos';
|
||||
override isLinuxApp = OS_TYPE === 'linux';
|
||||
override isMobileApp = ['android', 'ios'].includes(OS_TYPE);
|
||||
override isDesktopApp = ['macos', 'windows', 'linux'].includes(OS_TYPE);
|
||||
override hasTrafficLight = OS_TYPE === 'macos';
|
||||
override hasWindow = !(OS_TYPE === 'ios' || OS_TYPE === 'android');
|
||||
override hasWindowBar = !(OS_TYPE === 'ios' || OS_TYPE === 'android');
|
||||
@@ -310,9 +343,11 @@ export class NativeAppService extends BaseAppService {
|
||||
(OS_TYPE === 'ios' && getOSPlatform() === 'ios') || OS_TYPE === 'android';
|
||||
override canCustomRootDir = OS_TYPE !== 'ios';
|
||||
override distChannel = process.env['NEXT_PUBLIC_DIST_CHANNEL'] || 'readest';
|
||||
private execDir?: string = undefined;
|
||||
|
||||
override async init() {
|
||||
const execDir = await invoke<string>('get_executable_dir');
|
||||
this.execDir = execDir;
|
||||
if (
|
||||
process.env['NEXT_PUBLIC_PORTABLE_APP'] ||
|
||||
(await this.fs.exists(`${execDir}/${SETTINGS_FILENAME}`, 'None'))
|
||||
@@ -332,13 +367,22 @@ export class NativeAppService extends BaseAppService {
|
||||
execDir,
|
||||
});
|
||||
}
|
||||
await super.init();
|
||||
await this.prepareBooksDir();
|
||||
}
|
||||
|
||||
override resolvePath(fp: string, base: BaseDir): ResolvedPath {
|
||||
return this.fs.resolvePath(fp, base);
|
||||
}
|
||||
|
||||
async setCustomRootDir(customRootDir: string) {
|
||||
this.fs.resolvePath = getPathResolver({
|
||||
customRootDir,
|
||||
isPortable: this.isPortableApp,
|
||||
execDir: this.execDir,
|
||||
});
|
||||
await this.prepareBooksDir();
|
||||
}
|
||||
|
||||
async selectDirectory(): Promise<string> {
|
||||
const selected = await openDialog({
|
||||
directory: true,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { FileSystem, BaseDir, AppPlatform, ResolvedPath } from '@/types/system';
|
||||
import { FileSystem, BaseDir, AppPlatform, ResolvedPath, FileItem } from '@/types/system';
|
||||
import { getOSPlatform, isValidURL } from '@/utils/misc';
|
||||
import { RemoteFile } from '@/utils/file';
|
||||
import { isPWA } from './environment';
|
||||
import { BaseAppService } from './appService';
|
||||
import { LOCAL_BOOKS_SUBDIR, LOCAL_DATA_SUBDIR, LOCAL_FONTS_SUBDIR } from './constants';
|
||||
import { DATA_SUBDIR, LOCAL_BOOKS_SUBDIR, LOCAL_FONTS_SUBDIR } from './constants';
|
||||
|
||||
const basePrefix = async () => '';
|
||||
|
||||
const resolvePath = (path: string, base: BaseDir): ResolvedPath => {
|
||||
switch (base) {
|
||||
case 'Data':
|
||||
return { baseDir: 0, basePrefix, fp: `${LOCAL_DATA_SUBDIR}/${path}`, base };
|
||||
return { baseDir: 0, basePrefix, fp: `${DATA_SUBDIR}/${path}`, base };
|
||||
case 'Books':
|
||||
return { baseDir: 0, basePrefix, fp: `${LOCAL_BOOKS_SUBDIR}/${path}`, base };
|
||||
case 'Fonts':
|
||||
@@ -168,17 +168,27 @@ const indexedDBFileSystem: FileSystem = {
|
||||
const { fp } = this.resolvePath(path, base);
|
||||
const db = await openIndexedDB();
|
||||
|
||||
return new Promise<{ path: string; isDir: boolean }[]>((resolve, reject) => {
|
||||
return new Promise<FileItem[]>((resolve, reject) => {
|
||||
const transaction = db.transaction('files', 'readonly');
|
||||
const store = transaction.objectStore('files');
|
||||
const request = store.getAll();
|
||||
|
||||
request.onsuccess = () => {
|
||||
const files = request.result as { path: string }[];
|
||||
const files = request.result as { path: string; content: string | ArrayBuffer | Blob }[];
|
||||
resolve(
|
||||
files
|
||||
.filter((file) => file.path.startsWith(fp))
|
||||
.map((file) => ({ path: file.path.slice(fp.length + 1), isDir: false })),
|
||||
.map((file) => ({
|
||||
path: file.path.slice(fp.length + 1),
|
||||
size:
|
||||
file.content instanceof Blob
|
||||
? file.content.size
|
||||
: typeof file.content === 'string'
|
||||
? file.content.length
|
||||
: file.content instanceof ArrayBuffer
|
||||
? file.content.byteLength
|
||||
: 0,
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -208,13 +218,17 @@ export class WebAppService extends BaseAppService {
|
||||
|
||||
override async init() {
|
||||
await this.loadSettings();
|
||||
await super.init();
|
||||
await this.prepareBooksDir();
|
||||
}
|
||||
|
||||
override resolvePath(fp: string, base: BaseDir): ResolvedPath {
|
||||
return this.fs.resolvePath(fp, base);
|
||||
}
|
||||
|
||||
async setCustomRootDir() {
|
||||
// No-op in web environment
|
||||
}
|
||||
|
||||
async selectDirectory(): Promise<string> {
|
||||
throw new Error('selectDirectory is not supported in browser');
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export type AppPlatform = 'web' | 'tauri';
|
||||
export type OsPlatform = 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'unknown';
|
||||
export type BaseDir = 'Books' | 'Settings' | 'Data' | 'Fonts' | 'Log' | 'Cache' | 'Temp' | 'None';
|
||||
export type DeleteAction = 'cloud' | 'local' | 'both';
|
||||
export type SelectDirectoryMode = 'read' | 'write';
|
||||
|
||||
export type ResolvedPath = {
|
||||
baseDir: number;
|
||||
@@ -16,6 +17,11 @@ export type ResolvedPath = {
|
||||
base: BaseDir;
|
||||
};
|
||||
|
||||
export type FileItem = {
|
||||
path: string;
|
||||
size: number;
|
||||
};
|
||||
|
||||
export interface FileSystem {
|
||||
resolvePath(path: string, base: BaseDir): ResolvedPath;
|
||||
getURL(path: string): string;
|
||||
@@ -25,7 +31,7 @@ export interface FileSystem {
|
||||
readFile(path: string, base: BaseDir, mode: 'text' | 'binary'): Promise<string | ArrayBuffer>;
|
||||
writeFile(path: string, base: BaseDir, content: string | ArrayBuffer | File): Promise<void>;
|
||||
removeFile(path: string, base: BaseDir): Promise<void>;
|
||||
readDir(path: string, base: BaseDir): Promise<{ path: string; isDir: boolean }[]>;
|
||||
readDir(path: string, base: BaseDir): Promise<FileItem[]>;
|
||||
createDir(path: string, base: BaseDir, recursive?: boolean): Promise<void>;
|
||||
removeDir(path: string, base: BaseDir, recursive?: boolean): Promise<void>;
|
||||
exists(path: string, base: BaseDir): Promise<boolean>;
|
||||
@@ -52,14 +58,22 @@ export interface AppService {
|
||||
isMacOSApp: boolean;
|
||||
isLinuxApp: boolean;
|
||||
isPortableApp: boolean;
|
||||
isDesktopApp: boolean;
|
||||
distChannel: string;
|
||||
|
||||
init(): Promise<void>;
|
||||
openFile(path: string, base: BaseDir): Promise<File>;
|
||||
copyFile(srcPath: string, dstPath: string, base: BaseDir): Promise<void>;
|
||||
createDir(path: string, base: BaseDir, recursive?: boolean): Promise<void>;
|
||||
deleteFile(path: string, base: BaseDir): Promise<void>;
|
||||
deleteDir(path: string, base: BaseDir, recursive?: boolean): Promise<void>;
|
||||
|
||||
setCustomRootDir(customRootDir: string): Promise<void>;
|
||||
resolveFilePath(path: string, base: BaseDir): Promise<string>;
|
||||
getCachedImageUrl(pathOrUrl: string): Promise<string>;
|
||||
selectDirectory(): Promise<string>;
|
||||
selectDirectory(mode: SelectDirectoryMode): Promise<string>;
|
||||
selectFiles(name: string, extensions: string[]): Promise<string[]>;
|
||||
readDirectory(path: string, base: BaseDir): Promise<FileItem[]>;
|
||||
|
||||
getDefaultViewSettings(): ViewSettings;
|
||||
loadSettings(): Promise<SystemSettings>;
|
||||
|
||||
@@ -172,16 +172,18 @@ export const formatDate = (date: string | number | Date | null | undefined, isUT
|
||||
}
|
||||
};
|
||||
|
||||
export const formatFileSize = (size: number | null) => {
|
||||
if (size === null) return '';
|
||||
const formatter = new Intl.NumberFormat('en', {
|
||||
export const formatBytes = (bytes?: number | null, locale = 'en-US') => {
|
||||
if (!bytes) return '';
|
||||
const units = ['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
const value = bytes / Math.pow(1024, i);
|
||||
const formatter = new Intl.NumberFormat(locale, {
|
||||
style: 'unit',
|
||||
unit: 'byte',
|
||||
unitDisplay: 'narrow',
|
||||
notation: 'compact',
|
||||
compactDisplay: 'short',
|
||||
unit: units[i],
|
||||
unitDisplay: 'short',
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
return formatter.format(size);
|
||||
return formatter.format(value);
|
||||
};
|
||||
|
||||
export const getCurrentPage = (book: Book, progress: BookProgress) => {
|
||||
|
||||
Reference in New Issue
Block a user