From 32c9f76c932a40aa067a6584031afa52b8fb1d4c Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Thu, 11 Jun 2026 06:14:58 +0100 Subject: [PATCH] add type defs for community automatic review --- _types/LiveSyncBaseCore.d.ts | 134 + _types/common/KeyValueDB.d.ts | 3 + _types/common/KeyValueDBv2.d.ts | 24 + _types/common/PeriodicProcessor.d.ts | 12 + _types/common/SvelteItemView.d.ts | 9 + _types/common/events.d.ts | 36 + _types/common/obsidianEvents.d.ts | 14 + _types/common/reportTool.d.ts | 12 + _types/common/stores.d.ts | 3 + _types/common/types.d.ts | 47 + _types/common/utils.d.ts | 61 + _types/deps.d.ts | 6 + _types/features/ConfigSync/CmdConfigSync.d.ts | 147 + .../ConfigSync/PluginDialogModal.d.ts | 11 + .../HiddenFileCommon/JsonResolveModal.d.ts | 19 + .../HiddenFileSync/CmdHiddenFileSync.d.ts | 153 + _types/features/LiveSyncCommands.d.ts | 35 + .../CmdLocalDatabaseMainte.d.ts | 58 + .../P2POpenReplicationModal.d.ts | 21 + .../P2PReplicator/P2PReplicationUI.d.ts | 22 + .../P2PReplicator/P2PReplicatorPaneView.d.ts | 28 + .../P2PServerStatusPaneView.d.ts | 19 + _types/lib/_tools/bakei18n.d.ts | 1 + _types/lib/_tools/checkI18nCoverage.d.ts | 1 + _types/lib/_tools/decompileRosetta.d.ts | 1 + _types/lib/_tools/decompileRosettaToJson.d.ts | 1 + _types/lib/_tools/json2yaml.d.ts | 1 + _types/lib/_tools/messagelib.d.ts | 2 + _types/lib/_tools/yaml2json.d.ts | 1 + _types/lib/src/API/DirectFileManipulator.d.ts | 2 + _types/lib/src/API/processSetting.d.ts | 41 + .../src/ContentSplitter/ContentSplitter.d.ts | 24 + .../ContentSplitter/ContentSplitterBase.d.ts | 51 + .../ContentSplitterRabinKarp.d.ts | 9 + .../ContentSplitter/ContentSplitterV1.d.ts | 9 + .../ContentSplitter/ContentSplitterV2.d.ts | 9 + .../src/ContentSplitter/ContentSplitters.d.ts | 12 + _types/lib/src/UI/svelteDialog.d.ts | 2 + _types/lib/src/bureau/bureau.d.ts | 7 + _types/lib/src/cli/APITest.sample.d.ts | 1 + _types/lib/src/common/ConnectionString.d.ts | 30 + _types/lib/src/common/LSError.d.ts | 47 + _types/lib/src/common/configForDoc.d.ts | 78 + _types/lib/src/common/context.d.ts | 16 + _types/lib/src/common/coreEnvFunctions.d.ts | 21 + _types/lib/src/common/coreEnvVars.d.ts | 3 + _types/lib/src/common/i18n.d.ts | 18 + _types/lib/src/common/logger.d.ts | 2 + .../common/messages/combinedMessages.dev.d.ts | 7 + .../messages/combinedMessages.prod.d.ts | 9264 +++++++++++++++++ _types/lib/src/common/messages/de.d.ts | 297 + _types/lib/src/common/messages/def.d.ts | 1119 ++ _types/lib/src/common/messages/es.d.ts | 689 ++ _types/lib/src/common/messages/fr.d.ts | 582 ++ _types/lib/src/common/messages/he.d.ts | 583 ++ _types/lib/src/common/messages/ja.d.ts | 838 ++ _types/lib/src/common/messages/ko.d.ts | 800 ++ _types/lib/src/common/messages/ru.d.ts | 858 ++ _types/lib/src/common/messages/zh-tw.d.ts | 384 + _types/lib/src/common/messages/zh.d.ts | 1093 ++ _types/lib/src/common/models/auth.type.d.ts | 41 + _types/lib/src/common/models/db.const.d.ts | 20 + .../lib/src/common/models/db.definition.d.ts | 56 + _types/lib/src/common/models/db.type.d.ts | 175 + .../src/common/models/diff.definition.d.ts | 16 + .../src/common/models/fileaccess.const.d.ts | 7 + .../src/common/models/fileaccess.type.d.ts | 83 + .../lib/src/common/models/redflag.const.d.ts | 32 + .../lib/src/common/models/setting.const.d.ts | 49 + .../common/models/setting.const.defaults.d.ts | 3 + .../models/setting.const.preferred.d.ts | 5 + .../src/common/models/setting.const.qr.d.ts | 2 + .../lib/src/common/models/setting.type.d.ts | 893 ++ .../common/models/shared.const.behabiour.d.ts | 28 + .../lib/src/common/models/shared.const.d.ts | 5 + .../common/models/shared.const.symbols.d.ts | 9 + .../models/shared.definition.configNames.d.ts | 36 + .../src/common/models/shared.definition.d.ts | 22 + .../src/common/models/shared.type.util.d.ts | 8 + .../src/common/models/sync.definition.d.ts | 18 + .../src/common/models/tweak.definition.d.ts | 190 + _types/lib/src/common/rosetta.d.ts | 42 + _types/lib/src/common/settingConstants.d.ts | 215 + _types/lib/src/common/typeUtils.d.ts | 17 + _types/lib/src/common/types.d.ts | 107 + _types/lib/src/common/utils.concurrency.d.ts | 10 + _types/lib/src/common/utils.d.ts | 25 + _types/lib/src/common/utils.database.d.ts | 23 + _types/lib/src/common/utils.doc.d.ts | 8 + _types/lib/src/common/utils.misc.d.ts | 13 + _types/lib/src/common/utils.notations.d.ts | 6 + _types/lib/src/common/utils.object.d.ts | 2 + _types/lib/src/common/utils.patch.d.ts | 8 + _types/lib/src/common/utils.regexp.d.ts | 25 + _types/lib/src/common/utils.settings.d.ts | 19 + _types/lib/src/common/utils.timer.d.ts | 18 + _types/lib/src/dataobject/StoredMap.d.ts | 12 + _types/lib/src/dev/checks.d.ts | 5 + _types/lib/src/encryption/encryptHKDF.d.ts | 3 + .../lib/src/encryption/stringEncryption.d.ts | 27 + _types/lib/src/events/coreEvents.d.ts | 55 + _types/lib/src/hub/hub.d.ts | 8 + _types/lib/src/index.d.ts | 1 + _types/lib/src/interfaces/Confirm.d.ts | 17 + .../src/interfaces/DatabaseFileAccess.d.ts | 15 + .../lib/src/interfaces/DatabaseRebuilder.d.ts | 13 + _types/lib/src/interfaces/FileHandler.d.ts | 12 + .../lib/src/interfaces/KeyValueDatabase.d.ts | 9 + _types/lib/src/interfaces/ServiceModule.d.ts | 59 + _types/lib/src/interfaces/StorageAccess.d.ts | 44 + .../src/interfaces/StorageEventManager.d.ts | 17 + _types/lib/src/managers/ChangeManager.d.ts | 61 + _types/lib/src/managers/ChunkFetcher.d.ts | 35 + _types/lib/src/managers/ChunkManager.d.ts | 2 + _types/lib/src/managers/ConflictManager.d.ts | 39 + .../managers/EntryManager/EntryManager.d.ts | 38 + .../EntryManager/EntryManagerImpls.d.ts | 28 + .../src/managers/HashManager/HashManager.d.ts | 60 + .../managers/HashManager/HashManagerCore.d.ts | 114 + .../HashManager/PureJSHashManager.d.ts | 77 + .../HashManager/XXHashHashManager.d.ts | 96 + .../lib/src/managers/LayeredChunkManager.d.ts | 51 + .../LayeredChunkManager/ArrivalWaitLayer.d.ts | 32 + .../LayeredChunkManager/CacheLayer.d.ts | 59 + .../ChunkLayerInterfaces.d.ts | 37 + .../DatabaseReadLayer.d.ts | 15 + .../DatabaseWriteLayer.d.ts | 12 + .../LayeredChunkManager/HotPackLayer.d.ts | 9 + .../managers/LayeredChunkManager/types.d.ts | 33 + _types/lib/src/managers/LiveSyncManagers.d.ts | 49 + .../lib/src/managers/StorageEventManager.d.ts | 136 + .../managers/StorageProcessingManager.d.ts | 14 + .../IStorageEventConverterAdapter.d.ts | 17 + .../adapters/IStorageEventManagerAdapter.d.ts | 18 + .../IStorageEventPersistenceAdapter.d.ts | 15 + .../adapters/IStorageEventStatusAdapter.d.ts | 13 + .../IStorageEventTypeGuardAdapter.d.ts | 16 + .../adapters/IStorageEventWatchAdapter.d.ts | 21 + _types/lib/src/managers/adapters/index.d.ts | 6 + _types/lib/src/mock_and_interop/stores.d.ts | 21 + _types/lib/src/mock_and_interop/wrapper.d.ts | 7 + _types/lib/src/mods.d.ts | 1 + .../lib/src/pouchdb/LiveSyncDBFunctions.d.ts | 17 + _types/lib/src/pouchdb/LiveSyncLocalDB.d.ts | 98 + _types/lib/src/pouchdb/ReplicatorShim.d.ts | 51 + _types/lib/src/pouchdb/StreamingFetch.d.ts | 17 + _types/lib/src/pouchdb/chunks.d.ts | 38 + _types/lib/src/pouchdb/compress.d.ts | 11 + _types/lib/src/pouchdb/encryption.d.ts | 22 + _types/lib/src/pouchdb/negotiation.d.ts | 9 + _types/lib/src/pouchdb/pouchdb-browser.d.ts | 2 + _types/lib/src/pouchdb/pouchdb-http.d.ts | 2 + _types/lib/src/pouchdb/pouchdb-test.d.ts | 2 + _types/lib/src/pouchdb/utils_couchdb.d.ts | 4 + .../LiveSyncAbstractReplicator.d.ts | 71 + .../src/replication/SyncParamsHandler.d.ts | 35 + .../couchdb/LiveSyncReplicator.d.ts | 89 + _types/lib/src/replication/httplib.d.ts | 76 + .../journal/JournalSyncAbstract.d.ts | 89 + .../replication/journal/JournalSyncTypes.d.ts | 9 + .../journal/LiveSyncJournalReplicator.d.ts | 43 + .../journal/LiveSyncJournalReplicatorEnv.d.ts | 5 + .../journal/objectstore/JournalSyncMinio.d.ts | 15 + .../trystero/LiveSyncTrysteroReplicator.d.ts | 96 + .../replication/trystero/P2PLogCollector.d.ts | 7 + .../trystero/P2PReplicatorBase.d.ts | 20 + .../trystero/P2PReplicatorCore.d.ts | 12 + .../trystero/P2PReplicatorPaneCommon.d.ts | 41 + .../src/replication/trystero/ProxiedDB.d.ts | 12 + .../trystero/TrysteroReplicator.d.ts | 151 + .../trystero/TrysteroReplicatorP2PClient.d.ts | 19 + .../TrysteroReplicatorP2PConnection.d.ts | 2 + .../trystero/TrysteroReplicatorP2PServer.d.ts | 117 + .../trystero/UseP2PReplicatorResult.d.ts | 11 + .../trystero/addP2PEventHandlers.d.ts | 34 + .../src/replication/trystero/rpcCompat.d.ts | 1 + .../lib/src/replication/trystero/types.d.ts | 86 + .../trystero/useP2PReplicatorCommands.d.ts | 7 + .../trystero/useP2PReplicatorFeature.d.ts | 17 + _types/lib/src/rpc/RpcRoom.d.ts | 24 + _types/lib/src/rpc/RpcSession.d.ts | 9 + _types/lib/src/rpc/chunking.d.ts | 11 + _types/lib/src/rpc/errors.d.ts | 8 + _types/lib/src/rpc/index.d.ts | 6 + .../lib/src/rpc/pouchdb/RpcPouchDBProxy.d.ts | 75 + .../lib/src/rpc/pouchdb/RpcPouchDBServer.d.ts | 16 + .../transports/DiagRTCPeerConnections.d.ts | 24 + .../DiagRTCPeerConnections.types.d.ts | 64 + .../DiagRTCPeerConnections.utils.d.ts | 33 + .../src/rpc/transports/TrysteroTransport.d.ts | 216 + .../lib/src/rpc/transports/trysteroUtils.d.ts | 3 + _types/lib/src/rpc/types.d.ts | 75 + .../src/serviceFeatures/checkRemoteSize.d.ts | 28 + .../src/serviceFeatures/offlineScanner.d.ts | 131 + .../prepareDatabaseForUse.d.ts | 20 + .../lib/src/serviceFeatures/remoteConfig.d.ts | 46 + .../serviceFeatures/setupObsidian/qrCode.d.ts | 4 + .../setupObsidian/setupUri.d.ts | 7 + .../serviceFeatures/setupObsidian/types.d.ts | 2 + .../lib/src/serviceFeatures/targetFilter.d.ts | 24 + .../src/serviceModules/FileAccessBase.d.ts | 93 + _types/lib/src/serviceModules/Rebuilder.d.ts | 82 + .../ServiceDatabaseFileAccessBase.d.ts | 38 + .../serviceModules/ServiceFileAccessBase.d.ts | 65 + .../ServiceFileHandlerBase.d.ts | 49 + .../src/serviceModules/ServiceModuleBase.d.ts | 10 + .../adapters/IConversionAdapter.d.ts | 15 + .../adapters/IFileSystemAdapter.d.ts | 47 + .../serviceModules/adapters/IPathAdapter.d.ts | 15 + .../adapters/IStorageAdapter.d.ts | 54 + .../adapters/ITypeGuardAdapter.d.ts | 14 + .../adapters/IVaultAdapter.d.ts | 47 + .../src/serviceModules/adapters/index.d.ts | 6 + _types/lib/src/services/BrowserServices.d.ts | 7 + _types/lib/src/services/HeadlessServices.d.ts | 10 + .../lib/src/services/InjectableServices.d.ts | 1 + _types/lib/src/services/ServiceHub.d.ts | 81 + _types/lib/src/services/base/APIService.d.ts | 93 + .../services/base/AppLifecycleService.d.ts | 132 + .../lib/src/services/base/ConfigService.d.ts | 7 + .../src/services/base/ConflictService.d.ts | 55 + .../lib/src/services/base/ControlService.d.ts | 54 + .../services/base/DatabaseEventService.d.ts | 38 + .../src/services/base/DatabaseService.d.ts | 37 + .../services/base/FileProcessingService.d.ts | 25 + _types/lib/src/services/base/IService.d.ts | 282 + .../src/services/base/KeyValueDBService.d.ts | 40 + _types/lib/src/services/base/PathService.d.ts | 39 + .../lib/src/services/base/RemoteService.d.ts | 58 + .../src/services/base/ReplicationService.d.ts | 91 + .../src/services/base/ReplicatorService.d.ts | 54 + _types/lib/src/services/base/ServiceBase.d.ts | 6 + .../lib/src/services/base/SettingService.d.ts | 112 + _types/lib/src/services/base/TestService.d.ts | 28 + .../src/services/base/TweakValueService.d.ts | 41 + .../services/base/UnresolvedErrorManager.d.ts | 13 + .../lib/src/services/base/VaultService.d.ts | 69 + .../services/implements/base/UIService.d.ts | 26 + .../implements/browser/BrowserAPIService.d.ts | 51 + .../implements/browser/BrowserConfirm.d.ts | 21 + .../browser/BrowserDatabaseService.d.ts | 7 + .../implements/browser/BrowserUIService.d.ts | 17 + .../browser/ConfigServiceBrowserCompat.d.ts | 16 + .../src/services/implements/browser/Menu.d.ts | 26 + .../browser/ui/renderMessageMarkdown.d.ts | 1 + .../headless/HeadlessAPIService.d.ts | 52 + .../headless/HeadlessDatabaseService.d.ts | 7 + .../injectable/InjectableAPIService.d.ts | 7 + .../InjectableAppLifecycleService.d.ts | 11 + .../injectable/InjectableConflictService.d.ts | 11 + .../InjectableDatabaseEventService.d.ts | 4 + .../InjectableFileProcessingService.d.ts | 4 + .../injectable/InjectablePathService.d.ts | 13 + .../injectable/InjectableRemoteService.d.ts | 4 + .../InjectableReplicationService.d.ts | 4 + .../InjectableReplicatorService.d.ts | 4 + .../injectable/InjectableServiceHub.d.ts | 71 + .../injectable/InjectableServices.d.ts | 36 + .../injectable/InjectableSettingService.d.ts | 11 + .../injectable/InjectableTestService.d.ts | 5 + .../InjectableTweakValueService.d.ts | 15 + .../injectable/InjectableVaultService.d.ts | 9 + .../obsidian/ObsidianServiceContext.d.ts | 9 + _types/lib/src/services/lib/HandlerUtils.d.ts | 374 + .../lib/src/services/lib/MiddlewareUtils.d.ts | 29 + _types/lib/src/services/lib/logUtils.d.ts | 13 + _types/lib/src/string_and_binary/chunks.d.ts | 10 + _types/lib/src/string_and_binary/convert.d.ts | 8 + _types/lib/src/string_and_binary/hash.d.ts | 2 + _types/lib/src/string_and_binary/path.d.ts | 35 + _types/lib/src/system/wakelock.d.ts | 6 + _types/lib/src/worker/bg.common.d.ts | 2 + _types/lib/src/worker/bg.worker.d.ts | 1 + .../lib/src/worker/bg.worker.encryption.d.ts | 7 + .../lib/src/worker/bg.worker.splitting.d.ts | 6 + _types/lib/src/worker/bgWorker.d.ts | 82 + _types/lib/src/worker/bgWorker.mock.d.ts | 39 + _types/lib/src/worker/universalTypes.d.ts | 46 + _types/main.d.ts | 20 + .../ObsidianStorageEventManagerAdapter.d.ts | 65 + .../managers/StorageEventManagerObsidian.d.ts | 13 + _types/modules/AbstractModule.d.ts | 27 + _types/modules/AbstractObsidianModule.d.ts | 15 + _types/modules/ModuleTypes.d.ts | 30 + .../modules/core/ModulePeriodicProcess.d.ts | 14 + _types/modules/core/ModuleReplicator.d.ts | 24 + .../modules/core/ModuleReplicatorCouchDB.d.ts | 9 + .../modules/core/ModuleReplicatorMinIO.d.ts | 8 + .../core/ReplicateResultProcessor.d.ts | 115 + .../coreFeatures/ModuleConflictChecker.d.ts | 13 + .../coreFeatures/ModuleConflictResolver.d.ts | 18 + .../ModuleResolveMismatchedTweaks.d.ts | 35 + .../modules/coreObsidian/UILib/dialogs.d.ts | 53 + .../coreObsidian/storageLib/utilObsidian.d.ts | 10 + _types/modules/essential/ModuleBasicMenu.d.ts | 6 + _types/modules/essential/ModuleMigration.d.ts | 13 + .../APILib/ObsHttpHandler.d.ts | 16 + .../ModuleObsidianEvents.d.ts | 26 + .../essentialObsidian/ModuleObsidianMenu.d.ts | 6 + _types/modules/extras/ModuleDev.d.ts | 12 + .../modules/extras/devUtil/TestPaneView.d.ts | 24 + _types/modules/extras/devUtil/testUtils.d.ts | 3 + .../DocumentHistory/DocumentHistoryModal.d.ts | 69 + .../GlobalHistory/GlobalHistoryView.d.ts | 18 + .../ConflictResolveModal.d.ts | 34 + _types/modules/features/Log/LogPaneView.d.ts | 18 + .../modules/features/ModuleGlobalHistory.d.ts | 6 + .../ModuleInteractiveConflictResolver.d.ts | 12 + _types/modules/features/ModuleLog.d.ts | 47 + .../ModuleObsidianDocumentHistory.d.ts | 9 + .../ModuleObsidianSettingAsMarkdown.d.ts | 22 + .../features/ModuleObsidianSettingTab.d.ts | 10 + .../SettingDialogue/LiveSyncSetting.d.ts | 53 + .../ObsidianLiveSyncSettingTab.d.ts | 100 + .../SettingDialogue/PaneAdvanced.d.ts | 3 + .../SettingDialogue/PaneChangeLog.d.ts | 2 + .../PaneCustomisationSync.d.ts | 3 + .../features/SettingDialogue/PaneGeneral.d.ts | 3 + .../features/SettingDialogue/PaneHatch.d.ts | 3 + .../SettingDialogue/PaneMaintenance.d.ts | 3 + .../features/SettingDialogue/PanePatches.d.ts | 3 + .../SettingDialogue/PanePowerUsers.d.ts | 3 + .../SettingDialogue/PaneRemoteConfig.d.ts | 3 + .../SettingDialogue/PaneSelector.d.ts | 3 + .../features/SettingDialogue/PaneSetup.d.ts | 3 + .../SettingDialogue/PaneSyncSettings.d.ts | 3 + .../features/SettingDialogue/SettingPane.d.ts | 36 + .../features/SettingDialogue/SveltePanel.d.ts | 34 + .../SettingDialogue/remoteConfigBuffer.d.ts | 2 + .../SettingDialogue/settingConstants.d.ts | 1 + .../SettingDialogue/settingUtils.d.ts | 57 + _types/modules/features/SetupManager.d.ts | 119 + .../SetupWizard/dialogs/setupDialogTypes.d.ts | 49 + _types/modules/main/ModuleLiveSyncMain.d.ts | 9 + .../modules/services/ObsidianAPIService.d.ts | 39 + .../services/ObsidianAppLifecycleService.d.ts | 12 + _types/modules/services/ObsidianConfirm.d.ts | 24 + .../services/ObsidianDatabaseService.d.ts | 6 + .../modules/services/ObsidianPathService.d.ts | 12 + .../modules/services/ObsidianServiceHub.d.ts | 6 + _types/modules/services/ObsidianServices.d.ts | 34 + .../services/ObsidianSettingService.d.ts | 11 + .../modules/services/ObsidianUIService.d.ts | 17 + .../services/ObsidianVaultService.d.ts | 15 + .../services/SvelteDialogObsidian.d.ts | 9 + .../onLayoutReady/enablei18n.d.ts | 1 + _types/serviceFeatures/redFlag.d.ts | 37 + .../serviceFeatures/redFlag.simpleFetch.d.ts | 17 + _types/serviceFeatures/redFlag.utils.d.ts | 27 + .../setupObsidian/setupManagerHandlers.d.ts | 6 + .../setupObsidian/setupProtocol.d.ts | 6 + .../serviceFeatures/useP2PReplicatorUI.d.ts | 17 + _types/serviceModules/DatabaseFileAccess.d.ts | 4 + _types/serviceModules/FileAccessObsidian.d.ts | 10 + _types/serviceModules/FileHandler.d.ts | 3 + .../ObsidianConversionAdapter.d.ts | 10 + .../ObsidianFileSystemAdapter.d.ts | 29 + .../ObsidianPathAdapter.d.ts | 10 + .../ObsidianStorageAdapter.d.ts | 24 + .../ObsidianTypeGuardAdapter.d.ts | 9 + .../ObsidianVaultAdapter.d.ts | 20 + .../serviceModules/ServiceFileAccessImpl.d.ts | 4 + _types/types.d.ts | 24 + generate-types.mjs | 11 + package.json | 2 + tsconfig.json | 2 +- tsconfig.types.json | 22 + 367 files changed, 28411 insertions(+), 1 deletion(-) create mode 100644 _types/LiveSyncBaseCore.d.ts create mode 100644 _types/common/KeyValueDB.d.ts create mode 100644 _types/common/KeyValueDBv2.d.ts create mode 100644 _types/common/PeriodicProcessor.d.ts create mode 100644 _types/common/SvelteItemView.d.ts create mode 100644 _types/common/events.d.ts create mode 100644 _types/common/obsidianEvents.d.ts create mode 100644 _types/common/reportTool.d.ts create mode 100644 _types/common/stores.d.ts create mode 100644 _types/common/types.d.ts create mode 100644 _types/common/utils.d.ts create mode 100644 _types/deps.d.ts create mode 100644 _types/features/ConfigSync/CmdConfigSync.d.ts create mode 100644 _types/features/ConfigSync/PluginDialogModal.d.ts create mode 100644 _types/features/HiddenFileCommon/JsonResolveModal.d.ts create mode 100644 _types/features/HiddenFileSync/CmdHiddenFileSync.d.ts create mode 100644 _types/features/LiveSyncCommands.d.ts create mode 100644 _types/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.d.ts create mode 100644 _types/features/P2PSync/P2PReplicator/P2POpenReplicationModal.d.ts create mode 100644 _types/features/P2PSync/P2PReplicator/P2PReplicationUI.d.ts create mode 100644 _types/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.d.ts create mode 100644 _types/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.d.ts create mode 100644 _types/lib/_tools/bakei18n.d.ts create mode 100644 _types/lib/_tools/checkI18nCoverage.d.ts create mode 100644 _types/lib/_tools/decompileRosetta.d.ts create mode 100644 _types/lib/_tools/decompileRosettaToJson.d.ts create mode 100644 _types/lib/_tools/json2yaml.d.ts create mode 100644 _types/lib/_tools/messagelib.d.ts create mode 100644 _types/lib/_tools/yaml2json.d.ts create mode 100644 _types/lib/src/API/DirectFileManipulator.d.ts create mode 100644 _types/lib/src/API/processSetting.d.ts create mode 100644 _types/lib/src/ContentSplitter/ContentSplitter.d.ts create mode 100644 _types/lib/src/ContentSplitter/ContentSplitterBase.d.ts create mode 100644 _types/lib/src/ContentSplitter/ContentSplitterRabinKarp.d.ts create mode 100644 _types/lib/src/ContentSplitter/ContentSplitterV1.d.ts create mode 100644 _types/lib/src/ContentSplitter/ContentSplitterV2.d.ts create mode 100644 _types/lib/src/ContentSplitter/ContentSplitters.d.ts create mode 100644 _types/lib/src/UI/svelteDialog.d.ts create mode 100644 _types/lib/src/bureau/bureau.d.ts create mode 100644 _types/lib/src/cli/APITest.sample.d.ts create mode 100644 _types/lib/src/common/ConnectionString.d.ts create mode 100644 _types/lib/src/common/LSError.d.ts create mode 100644 _types/lib/src/common/configForDoc.d.ts create mode 100644 _types/lib/src/common/context.d.ts create mode 100644 _types/lib/src/common/coreEnvFunctions.d.ts create mode 100644 _types/lib/src/common/coreEnvVars.d.ts create mode 100644 _types/lib/src/common/i18n.d.ts create mode 100644 _types/lib/src/common/logger.d.ts create mode 100644 _types/lib/src/common/messages/combinedMessages.dev.d.ts create mode 100644 _types/lib/src/common/messages/combinedMessages.prod.d.ts create mode 100644 _types/lib/src/common/messages/de.d.ts create mode 100644 _types/lib/src/common/messages/def.d.ts create mode 100644 _types/lib/src/common/messages/es.d.ts create mode 100644 _types/lib/src/common/messages/fr.d.ts create mode 100644 _types/lib/src/common/messages/he.d.ts create mode 100644 _types/lib/src/common/messages/ja.d.ts create mode 100644 _types/lib/src/common/messages/ko.d.ts create mode 100644 _types/lib/src/common/messages/ru.d.ts create mode 100644 _types/lib/src/common/messages/zh-tw.d.ts create mode 100644 _types/lib/src/common/messages/zh.d.ts create mode 100644 _types/lib/src/common/models/auth.type.d.ts create mode 100644 _types/lib/src/common/models/db.const.d.ts create mode 100644 _types/lib/src/common/models/db.definition.d.ts create mode 100644 _types/lib/src/common/models/db.type.d.ts create mode 100644 _types/lib/src/common/models/diff.definition.d.ts create mode 100644 _types/lib/src/common/models/fileaccess.const.d.ts create mode 100644 _types/lib/src/common/models/fileaccess.type.d.ts create mode 100644 _types/lib/src/common/models/redflag.const.d.ts create mode 100644 _types/lib/src/common/models/setting.const.d.ts create mode 100644 _types/lib/src/common/models/setting.const.defaults.d.ts create mode 100644 _types/lib/src/common/models/setting.const.preferred.d.ts create mode 100644 _types/lib/src/common/models/setting.const.qr.d.ts create mode 100644 _types/lib/src/common/models/setting.type.d.ts create mode 100644 _types/lib/src/common/models/shared.const.behabiour.d.ts create mode 100644 _types/lib/src/common/models/shared.const.d.ts create mode 100644 _types/lib/src/common/models/shared.const.symbols.d.ts create mode 100644 _types/lib/src/common/models/shared.definition.configNames.d.ts create mode 100644 _types/lib/src/common/models/shared.definition.d.ts create mode 100644 _types/lib/src/common/models/shared.type.util.d.ts create mode 100644 _types/lib/src/common/models/sync.definition.d.ts create mode 100644 _types/lib/src/common/models/tweak.definition.d.ts create mode 100644 _types/lib/src/common/rosetta.d.ts create mode 100644 _types/lib/src/common/settingConstants.d.ts create mode 100644 _types/lib/src/common/typeUtils.d.ts create mode 100644 _types/lib/src/common/types.d.ts create mode 100644 _types/lib/src/common/utils.concurrency.d.ts create mode 100644 _types/lib/src/common/utils.d.ts create mode 100644 _types/lib/src/common/utils.database.d.ts create mode 100644 _types/lib/src/common/utils.doc.d.ts create mode 100644 _types/lib/src/common/utils.misc.d.ts create mode 100644 _types/lib/src/common/utils.notations.d.ts create mode 100644 _types/lib/src/common/utils.object.d.ts create mode 100644 _types/lib/src/common/utils.patch.d.ts create mode 100644 _types/lib/src/common/utils.regexp.d.ts create mode 100644 _types/lib/src/common/utils.settings.d.ts create mode 100644 _types/lib/src/common/utils.timer.d.ts create mode 100644 _types/lib/src/dataobject/StoredMap.d.ts create mode 100644 _types/lib/src/dev/checks.d.ts create mode 100644 _types/lib/src/encryption/encryptHKDF.d.ts create mode 100644 _types/lib/src/encryption/stringEncryption.d.ts create mode 100644 _types/lib/src/events/coreEvents.d.ts create mode 100644 _types/lib/src/hub/hub.d.ts create mode 100644 _types/lib/src/index.d.ts create mode 100644 _types/lib/src/interfaces/Confirm.d.ts create mode 100644 _types/lib/src/interfaces/DatabaseFileAccess.d.ts create mode 100644 _types/lib/src/interfaces/DatabaseRebuilder.d.ts create mode 100644 _types/lib/src/interfaces/FileHandler.d.ts create mode 100644 _types/lib/src/interfaces/KeyValueDatabase.d.ts create mode 100644 _types/lib/src/interfaces/ServiceModule.d.ts create mode 100644 _types/lib/src/interfaces/StorageAccess.d.ts create mode 100644 _types/lib/src/interfaces/StorageEventManager.d.ts create mode 100644 _types/lib/src/managers/ChangeManager.d.ts create mode 100644 _types/lib/src/managers/ChunkFetcher.d.ts create mode 100644 _types/lib/src/managers/ChunkManager.d.ts create mode 100644 _types/lib/src/managers/ConflictManager.d.ts create mode 100644 _types/lib/src/managers/EntryManager/EntryManager.d.ts create mode 100644 _types/lib/src/managers/EntryManager/EntryManagerImpls.d.ts create mode 100644 _types/lib/src/managers/HashManager/HashManager.d.ts create mode 100644 _types/lib/src/managers/HashManager/HashManagerCore.d.ts create mode 100644 _types/lib/src/managers/HashManager/PureJSHashManager.d.ts create mode 100644 _types/lib/src/managers/HashManager/XXHashHashManager.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/ArrivalWaitLayer.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/CacheLayer.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/ChunkLayerInterfaces.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/DatabaseReadLayer.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/DatabaseWriteLayer.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/HotPackLayer.d.ts create mode 100644 _types/lib/src/managers/LayeredChunkManager/types.d.ts create mode 100644 _types/lib/src/managers/LiveSyncManagers.d.ts create mode 100644 _types/lib/src/managers/StorageEventManager.d.ts create mode 100644 _types/lib/src/managers/StorageProcessingManager.d.ts create mode 100644 _types/lib/src/managers/adapters/IStorageEventConverterAdapter.d.ts create mode 100644 _types/lib/src/managers/adapters/IStorageEventManagerAdapter.d.ts create mode 100644 _types/lib/src/managers/adapters/IStorageEventPersistenceAdapter.d.ts create mode 100644 _types/lib/src/managers/adapters/IStorageEventStatusAdapter.d.ts create mode 100644 _types/lib/src/managers/adapters/IStorageEventTypeGuardAdapter.d.ts create mode 100644 _types/lib/src/managers/adapters/IStorageEventWatchAdapter.d.ts create mode 100644 _types/lib/src/managers/adapters/index.d.ts create mode 100644 _types/lib/src/mock_and_interop/stores.d.ts create mode 100644 _types/lib/src/mock_and_interop/wrapper.d.ts create mode 100644 _types/lib/src/mods.d.ts create mode 100644 _types/lib/src/pouchdb/LiveSyncDBFunctions.d.ts create mode 100644 _types/lib/src/pouchdb/LiveSyncLocalDB.d.ts create mode 100644 _types/lib/src/pouchdb/ReplicatorShim.d.ts create mode 100644 _types/lib/src/pouchdb/StreamingFetch.d.ts create mode 100644 _types/lib/src/pouchdb/chunks.d.ts create mode 100644 _types/lib/src/pouchdb/compress.d.ts create mode 100644 _types/lib/src/pouchdb/encryption.d.ts create mode 100644 _types/lib/src/pouchdb/negotiation.d.ts create mode 100644 _types/lib/src/pouchdb/pouchdb-browser.d.ts create mode 100644 _types/lib/src/pouchdb/pouchdb-http.d.ts create mode 100644 _types/lib/src/pouchdb/pouchdb-test.d.ts create mode 100644 _types/lib/src/pouchdb/utils_couchdb.d.ts create mode 100644 _types/lib/src/replication/LiveSyncAbstractReplicator.d.ts create mode 100644 _types/lib/src/replication/SyncParamsHandler.d.ts create mode 100644 _types/lib/src/replication/couchdb/LiveSyncReplicator.d.ts create mode 100644 _types/lib/src/replication/httplib.d.ts create mode 100644 _types/lib/src/replication/journal/JournalSyncAbstract.d.ts create mode 100644 _types/lib/src/replication/journal/JournalSyncTypes.d.ts create mode 100644 _types/lib/src/replication/journal/LiveSyncJournalReplicator.d.ts create mode 100644 _types/lib/src/replication/journal/LiveSyncJournalReplicatorEnv.d.ts create mode 100644 _types/lib/src/replication/journal/objectstore/JournalSyncMinio.d.ts create mode 100644 _types/lib/src/replication/trystero/LiveSyncTrysteroReplicator.d.ts create mode 100644 _types/lib/src/replication/trystero/P2PLogCollector.d.ts create mode 100644 _types/lib/src/replication/trystero/P2PReplicatorBase.d.ts create mode 100644 _types/lib/src/replication/trystero/P2PReplicatorCore.d.ts create mode 100644 _types/lib/src/replication/trystero/P2PReplicatorPaneCommon.d.ts create mode 100644 _types/lib/src/replication/trystero/ProxiedDB.d.ts create mode 100644 _types/lib/src/replication/trystero/TrysteroReplicator.d.ts create mode 100644 _types/lib/src/replication/trystero/TrysteroReplicatorP2PClient.d.ts create mode 100644 _types/lib/src/replication/trystero/TrysteroReplicatorP2PConnection.d.ts create mode 100644 _types/lib/src/replication/trystero/TrysteroReplicatorP2PServer.d.ts create mode 100644 _types/lib/src/replication/trystero/UseP2PReplicatorResult.d.ts create mode 100644 _types/lib/src/replication/trystero/addP2PEventHandlers.d.ts create mode 100644 _types/lib/src/replication/trystero/rpcCompat.d.ts create mode 100644 _types/lib/src/replication/trystero/types.d.ts create mode 100644 _types/lib/src/replication/trystero/useP2PReplicatorCommands.d.ts create mode 100644 _types/lib/src/replication/trystero/useP2PReplicatorFeature.d.ts create mode 100644 _types/lib/src/rpc/RpcRoom.d.ts create mode 100644 _types/lib/src/rpc/RpcSession.d.ts create mode 100644 _types/lib/src/rpc/chunking.d.ts create mode 100644 _types/lib/src/rpc/errors.d.ts create mode 100644 _types/lib/src/rpc/index.d.ts create mode 100644 _types/lib/src/rpc/pouchdb/RpcPouchDBProxy.d.ts create mode 100644 _types/lib/src/rpc/pouchdb/RpcPouchDBServer.d.ts create mode 100644 _types/lib/src/rpc/transports/DiagRTCPeerConnections.d.ts create mode 100644 _types/lib/src/rpc/transports/DiagRTCPeerConnections.types.d.ts create mode 100644 _types/lib/src/rpc/transports/DiagRTCPeerConnections.utils.d.ts create mode 100644 _types/lib/src/rpc/transports/TrysteroTransport.d.ts create mode 100644 _types/lib/src/rpc/transports/trysteroUtils.d.ts create mode 100644 _types/lib/src/rpc/types.d.ts create mode 100644 _types/lib/src/serviceFeatures/checkRemoteSize.d.ts create mode 100644 _types/lib/src/serviceFeatures/offlineScanner.d.ts create mode 100644 _types/lib/src/serviceFeatures/prepareDatabaseForUse.d.ts create mode 100644 _types/lib/src/serviceFeatures/remoteConfig.d.ts create mode 100644 _types/lib/src/serviceFeatures/setupObsidian/qrCode.d.ts create mode 100644 _types/lib/src/serviceFeatures/setupObsidian/setupUri.d.ts create mode 100644 _types/lib/src/serviceFeatures/setupObsidian/types.d.ts create mode 100644 _types/lib/src/serviceFeatures/targetFilter.d.ts create mode 100644 _types/lib/src/serviceModules/FileAccessBase.d.ts create mode 100644 _types/lib/src/serviceModules/Rebuilder.d.ts create mode 100644 _types/lib/src/serviceModules/ServiceDatabaseFileAccessBase.d.ts create mode 100644 _types/lib/src/serviceModules/ServiceFileAccessBase.d.ts create mode 100644 _types/lib/src/serviceModules/ServiceFileHandlerBase.d.ts create mode 100644 _types/lib/src/serviceModules/ServiceModuleBase.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/IConversionAdapter.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/IFileSystemAdapter.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/IPathAdapter.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/IStorageAdapter.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/ITypeGuardAdapter.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/IVaultAdapter.d.ts create mode 100644 _types/lib/src/serviceModules/adapters/index.d.ts create mode 100644 _types/lib/src/services/BrowserServices.d.ts create mode 100644 _types/lib/src/services/HeadlessServices.d.ts create mode 100644 _types/lib/src/services/InjectableServices.d.ts create mode 100644 _types/lib/src/services/ServiceHub.d.ts create mode 100644 _types/lib/src/services/base/APIService.d.ts create mode 100644 _types/lib/src/services/base/AppLifecycleService.d.ts create mode 100644 _types/lib/src/services/base/ConfigService.d.ts create mode 100644 _types/lib/src/services/base/ConflictService.d.ts create mode 100644 _types/lib/src/services/base/ControlService.d.ts create mode 100644 _types/lib/src/services/base/DatabaseEventService.d.ts create mode 100644 _types/lib/src/services/base/DatabaseService.d.ts create mode 100644 _types/lib/src/services/base/FileProcessingService.d.ts create mode 100644 _types/lib/src/services/base/IService.d.ts create mode 100644 _types/lib/src/services/base/KeyValueDBService.d.ts create mode 100644 _types/lib/src/services/base/PathService.d.ts create mode 100644 _types/lib/src/services/base/RemoteService.d.ts create mode 100644 _types/lib/src/services/base/ReplicationService.d.ts create mode 100644 _types/lib/src/services/base/ReplicatorService.d.ts create mode 100644 _types/lib/src/services/base/ServiceBase.d.ts create mode 100644 _types/lib/src/services/base/SettingService.d.ts create mode 100644 _types/lib/src/services/base/TestService.d.ts create mode 100644 _types/lib/src/services/base/TweakValueService.d.ts create mode 100644 _types/lib/src/services/base/UnresolvedErrorManager.d.ts create mode 100644 _types/lib/src/services/base/VaultService.d.ts create mode 100644 _types/lib/src/services/implements/base/UIService.d.ts create mode 100644 _types/lib/src/services/implements/browser/BrowserAPIService.d.ts create mode 100644 _types/lib/src/services/implements/browser/BrowserConfirm.d.ts create mode 100644 _types/lib/src/services/implements/browser/BrowserDatabaseService.d.ts create mode 100644 _types/lib/src/services/implements/browser/BrowserUIService.d.ts create mode 100644 _types/lib/src/services/implements/browser/ConfigServiceBrowserCompat.d.ts create mode 100644 _types/lib/src/services/implements/browser/Menu.d.ts create mode 100644 _types/lib/src/services/implements/browser/ui/renderMessageMarkdown.d.ts create mode 100644 _types/lib/src/services/implements/headless/HeadlessAPIService.d.ts create mode 100644 _types/lib/src/services/implements/headless/HeadlessDatabaseService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableAPIService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableAppLifecycleService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableConflictService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableDatabaseEventService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableFileProcessingService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectablePathService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableRemoteService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableReplicationService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableReplicatorService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableServiceHub.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableServices.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableSettingService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableTestService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableTweakValueService.d.ts create mode 100644 _types/lib/src/services/implements/injectable/InjectableVaultService.d.ts create mode 100644 _types/lib/src/services/implements/obsidian/ObsidianServiceContext.d.ts create mode 100644 _types/lib/src/services/lib/HandlerUtils.d.ts create mode 100644 _types/lib/src/services/lib/MiddlewareUtils.d.ts create mode 100644 _types/lib/src/services/lib/logUtils.d.ts create mode 100644 _types/lib/src/string_and_binary/chunks.d.ts create mode 100644 _types/lib/src/string_and_binary/convert.d.ts create mode 100644 _types/lib/src/string_and_binary/hash.d.ts create mode 100644 _types/lib/src/string_and_binary/path.d.ts create mode 100644 _types/lib/src/system/wakelock.d.ts create mode 100644 _types/lib/src/worker/bg.common.d.ts create mode 100644 _types/lib/src/worker/bg.worker.d.ts create mode 100644 _types/lib/src/worker/bg.worker.encryption.d.ts create mode 100644 _types/lib/src/worker/bg.worker.splitting.d.ts create mode 100644 _types/lib/src/worker/bgWorker.d.ts create mode 100644 _types/lib/src/worker/bgWorker.mock.d.ts create mode 100644 _types/lib/src/worker/universalTypes.d.ts create mode 100644 _types/main.d.ts create mode 100644 _types/managers/ObsidianStorageEventManagerAdapter.d.ts create mode 100644 _types/managers/StorageEventManagerObsidian.d.ts create mode 100644 _types/modules/AbstractModule.d.ts create mode 100644 _types/modules/AbstractObsidianModule.d.ts create mode 100644 _types/modules/ModuleTypes.d.ts create mode 100644 _types/modules/core/ModulePeriodicProcess.d.ts create mode 100644 _types/modules/core/ModuleReplicator.d.ts create mode 100644 _types/modules/core/ModuleReplicatorCouchDB.d.ts create mode 100644 _types/modules/core/ModuleReplicatorMinIO.d.ts create mode 100644 _types/modules/core/ReplicateResultProcessor.d.ts create mode 100644 _types/modules/coreFeatures/ModuleConflictChecker.d.ts create mode 100644 _types/modules/coreFeatures/ModuleConflictResolver.d.ts create mode 100644 _types/modules/coreFeatures/ModuleResolveMismatchedTweaks.d.ts create mode 100644 _types/modules/coreObsidian/UILib/dialogs.d.ts create mode 100644 _types/modules/coreObsidian/storageLib/utilObsidian.d.ts create mode 100644 _types/modules/essential/ModuleBasicMenu.d.ts create mode 100644 _types/modules/essential/ModuleMigration.d.ts create mode 100644 _types/modules/essentialObsidian/APILib/ObsHttpHandler.d.ts create mode 100644 _types/modules/essentialObsidian/ModuleObsidianEvents.d.ts create mode 100644 _types/modules/essentialObsidian/ModuleObsidianMenu.d.ts create mode 100644 _types/modules/extras/ModuleDev.d.ts create mode 100644 _types/modules/extras/devUtil/TestPaneView.d.ts create mode 100644 _types/modules/extras/devUtil/testUtils.d.ts create mode 100644 _types/modules/features/DocumentHistory/DocumentHistoryModal.d.ts create mode 100644 _types/modules/features/GlobalHistory/GlobalHistoryView.d.ts create mode 100644 _types/modules/features/InteractiveConflictResolving/ConflictResolveModal.d.ts create mode 100644 _types/modules/features/Log/LogPaneView.d.ts create mode 100644 _types/modules/features/ModuleGlobalHistory.d.ts create mode 100644 _types/modules/features/ModuleInteractiveConflictResolver.d.ts create mode 100644 _types/modules/features/ModuleLog.d.ts create mode 100644 _types/modules/features/ModuleObsidianDocumentHistory.d.ts create mode 100644 _types/modules/features/ModuleObsidianSettingAsMarkdown.d.ts create mode 100644 _types/modules/features/ModuleObsidianSettingTab.d.ts create mode 100644 _types/modules/features/SettingDialogue/LiveSyncSetting.d.ts create mode 100644 _types/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneAdvanced.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneChangeLog.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneCustomisationSync.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneGeneral.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneHatch.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneMaintenance.d.ts create mode 100644 _types/modules/features/SettingDialogue/PanePatches.d.ts create mode 100644 _types/modules/features/SettingDialogue/PanePowerUsers.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneRemoteConfig.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneSelector.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneSetup.d.ts create mode 100644 _types/modules/features/SettingDialogue/PaneSyncSettings.d.ts create mode 100644 _types/modules/features/SettingDialogue/SettingPane.d.ts create mode 100644 _types/modules/features/SettingDialogue/SveltePanel.d.ts create mode 100644 _types/modules/features/SettingDialogue/remoteConfigBuffer.d.ts create mode 100644 _types/modules/features/SettingDialogue/settingConstants.d.ts create mode 100644 _types/modules/features/SettingDialogue/settingUtils.d.ts create mode 100644 _types/modules/features/SetupManager.d.ts create mode 100644 _types/modules/features/SetupWizard/dialogs/setupDialogTypes.d.ts create mode 100644 _types/modules/main/ModuleLiveSyncMain.d.ts create mode 100644 _types/modules/services/ObsidianAPIService.d.ts create mode 100644 _types/modules/services/ObsidianAppLifecycleService.d.ts create mode 100644 _types/modules/services/ObsidianConfirm.d.ts create mode 100644 _types/modules/services/ObsidianDatabaseService.d.ts create mode 100644 _types/modules/services/ObsidianPathService.d.ts create mode 100644 _types/modules/services/ObsidianServiceHub.d.ts create mode 100644 _types/modules/services/ObsidianServices.d.ts create mode 100644 _types/modules/services/ObsidianSettingService.d.ts create mode 100644 _types/modules/services/ObsidianUIService.d.ts create mode 100644 _types/modules/services/ObsidianVaultService.d.ts create mode 100644 _types/modules/services/SvelteDialogObsidian.d.ts create mode 100644 _types/serviceFeatures/onLayoutReady/enablei18n.d.ts create mode 100644 _types/serviceFeatures/redFlag.d.ts create mode 100644 _types/serviceFeatures/redFlag.simpleFetch.d.ts create mode 100644 _types/serviceFeatures/redFlag.utils.d.ts create mode 100644 _types/serviceFeatures/setupObsidian/setupManagerHandlers.d.ts create mode 100644 _types/serviceFeatures/setupObsidian/setupProtocol.d.ts create mode 100644 _types/serviceFeatures/useP2PReplicatorUI.d.ts create mode 100644 _types/serviceModules/DatabaseFileAccess.d.ts create mode 100644 _types/serviceModules/FileAccessObsidian.d.ts create mode 100644 _types/serviceModules/FileHandler.d.ts create mode 100644 _types/serviceModules/FileSystemAdapters/ObsidianConversionAdapter.d.ts create mode 100644 _types/serviceModules/FileSystemAdapters/ObsidianFileSystemAdapter.d.ts create mode 100644 _types/serviceModules/FileSystemAdapters/ObsidianPathAdapter.d.ts create mode 100644 _types/serviceModules/FileSystemAdapters/ObsidianStorageAdapter.d.ts create mode 100644 _types/serviceModules/FileSystemAdapters/ObsidianTypeGuardAdapter.d.ts create mode 100644 _types/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.d.ts create mode 100644 _types/serviceModules/ServiceFileAccessImpl.d.ts create mode 100644 _types/types.d.ts create mode 100644 generate-types.mjs create mode 100644 tsconfig.types.json diff --git a/_types/LiveSyncBaseCore.d.ts b/_types/LiveSyncBaseCore.d.ts new file mode 100644 index 0000000..56caf94 --- /dev/null +++ b/_types/LiveSyncBaseCore.d.ts @@ -0,0 +1,134 @@ +import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase"; +import type { HasSettings, ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { DatabaseFileAccess } from "@lib/interfaces/DatabaseFileAccess"; +import type { Rebuilder } from "@lib/interfaces/DatabaseRebuilder"; +import type { IFileHandler } from "@lib/interfaces/FileHandler"; +import type { StorageAccess } from "@lib/interfaces/StorageAccess"; +import type { LiveSyncLocalDBEnv } from "@lib/pouchdb/LiveSyncLocalDB"; +import type { LiveSyncCouchDBReplicatorEnv } from "@lib/replication/couchdb/LiveSyncReplicator"; +import type { CheckPointInfo } from "@lib/replication/journal/JournalSyncTypes"; +import type { LiveSyncJournalReplicatorEnv } from "@lib/replication/journal/LiveSyncJournalReplicatorEnv"; +import type { LiveSyncReplicatorEnv } from "@lib/replication/LiveSyncAbstractReplicator"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices"; +import { AbstractModule } from "./modules/AbstractModule"; +import type { ServiceModules } from "@lib/interfaces/ServiceModule"; +export declare class LiveSyncBaseCore implements LiveSyncLocalDBEnv, LiveSyncReplicatorEnv, LiveSyncJournalReplicatorEnv, LiveSyncCouchDBReplicatorEnv, HasSettings { + addOns: TCommands[]; + /** + * register an add-onn to the plug-in. + * Add-ons are features that are not essential to the core functionality of the plugin, + * @param addOn + */ + private _registerAddOn; + /** + * Get an add-on by its class name. Returns undefined if not found. + * @param cls + * @returns + */ + getAddOn(cls: string): T | undefined; + constructor(serviceHub: InjectableServiceHub, serviceModuleInitialiser: (core: LiveSyncBaseCore, serviceHub: InjectableServiceHub) => ServiceModules, extraModuleInitialiser: (core: LiveSyncBaseCore) => AbstractModule[], addOnsInitialiser: (core: LiveSyncBaseCore) => TCommands[], featuresInitialiser: (core: LiveSyncBaseCore) => void); + /** + * The service hub for managing all services. + */ + _services: InjectableServiceHub | undefined; + get services(): InjectableServiceHub; + /** + * Service Modules + */ + protected _serviceModules: ServiceModules; + get serviceModules(): ServiceModules; + /** + * The modules of the plug-in. Modules are responsible for specific features or functionalities of the plug-in, such as file handling, conflict resolution, replication, etc. + */ + private modules; + /** + * Get a module by its class. Throws an error if not found. + * Mostly used for getting SetupManager. + * @param constructor + * @returns + */ + getModule(constructor: new (...args: any[]) => T): T; + /** + * Register a module to the plug-in. + * @param module The module to register. + */ + private _registerModule; + registerModules(extraModules?: AbstractModule[]): void; + /** + * Bind module functions to services. + */ + bindModuleFunctions(): void; + /** + * @obsolete Use services.UI.confirm instead. The confirm function to show a confirmation dialog to the user. + */ + get confirm(): Confirm; + /** + * @obsolete Use services.setting.currentSettings instead. The current settings of the plug-in. + */ + get settings(): ObsidianLiveSyncSettings; + /** + * @obsolete Use services.setting.settings instead. Set the settings of the plug-in. + */ + set settings(value: ObsidianLiveSyncSettings); + /** + * @obsolete Use services.setting.currentSettings instead. Get the settings of the plug-in. + * @returns The current settings of the plug-in. + */ + getSettings(): ObsidianLiveSyncSettings; + /** + * @obsolete Use services.database.localDatabase instead. The local database instance. + */ + get localDatabase(): import("@lib/pouchdb/LiveSyncLocalDB").LiveSyncLocalDB; + /** + * @obsolete Use services.database.localDatabase instead. Get the PouchDB database instance. Note that this is not the same as the local database instance, which is a wrapper around the PouchDB database. + * @returns The PouchDB database instance. + */ + getDatabase(): PouchDB.Database; + /** + * @obsolete Use services.keyValueDB.simpleStore instead. A simple key-value store for storing non-file data, such as checkpoints, sync status, etc. + */ + get simpleStore(): SimpleStore; + /** + * @obsolete Use services.replication.getActiveReplicator instead. Get the active replicator instance. Note that there can be multiple replicators, but only one can be active at a time. + */ + get replicator(): import("@lib/replication/LiveSyncAbstractReplicator").LiveSyncAbstractReplicator; + /** + * @obsolete Use services.keyValueDB.kvDB instead. Get the key-value database instance. This is used for storing large data that cannot be stored in the simple store, such as file metadata, etc. + */ + get kvDB(): import("./lib/src/interfaces/KeyValueDatabase").KeyValueDatabase; + /** + * Storage Accessor for handling file operations. + * @obsolete Use serviceModules.storageAccess instead. + */ + get storageAccess(): StorageAccess; + /** + * Database File Accessor for handling file operations related to the database, such as exporting the database, importing from a file, etc. + * @obsolete Use serviceModules.databaseFileAccess instead. + */ + get databaseFileAccess(): DatabaseFileAccess; + /** + * File Handler for handling file operations related to replication, such as resolving conflicts, applying changes from replication, etc. + * @obsolete Use serviceModules.fileHandler instead. + */ + get fileHandler(): IFileHandler; + /** + * Rebuilder for handling database rebuilding operations. + * @obsolete Use serviceModules.rebuilder instead. + */ + get rebuilder(): Rebuilder; + /** + * Initialise ServiceFeatures. + * (Please refer `serviceFeatures` for more details) + */ + initialiseServiceFeatures(): void; +} +export interface IMinimumLiveSyncCommands { + onunload(): void; + onload(): void | Promise; + constructor: { + name: string; + }; +} diff --git a/_types/common/KeyValueDB.d.ts b/_types/common/KeyValueDB.d.ts new file mode 100644 index 0000000..4b0e2ab --- /dev/null +++ b/_types/common/KeyValueDB.d.ts @@ -0,0 +1,3 @@ +import type { KeyValueDatabase } from "@lib/interfaces/KeyValueDatabase.ts"; +export { OpenKeyValueDatabase } from "./KeyValueDBv2.ts"; +export declare const _OpenKeyValueDatabase: (dbKey: string) => Promise; diff --git a/_types/common/KeyValueDBv2.d.ts b/_types/common/KeyValueDBv2.d.ts new file mode 100644 index 0000000..fba274f --- /dev/null +++ b/_types/common/KeyValueDBv2.d.ts @@ -0,0 +1,24 @@ +import type { KeyValueDatabase } from "@lib/interfaces/KeyValueDatabase"; +import { type IDBPDatabase } from "idb"; +export declare function OpenKeyValueDatabase(dbKey: string): Promise; +export declare class IDBKeyValueDatabase implements KeyValueDatabase { + protected _dbPromise: Promise> | null; + protected dbKey: string; + protected storeKey: string; + protected _isDestroyed: boolean; + protected destroyedPromise: Promise | null; + get isDestroyed(): boolean; + get ensuredDestroyed(): Promise; + getIsReady(): Promise; + protected ensureDB(): Promise>; + protected closeDB(setDestroyed?: boolean): Promise; + get DB(): Promise>; + constructor(dbKey: string); + get(key: IDBValidKey): Promise; + set(key: IDBValidKey, value: U): Promise; + del(key: IDBValidKey): Promise; + clear(): Promise; + keys(query?: IDBValidKey | IDBKeyRange, count?: number): Promise; + close(): Promise; + destroy(): Promise; +} diff --git a/_types/common/PeriodicProcessor.d.ts b/_types/common/PeriodicProcessor.d.ts new file mode 100644 index 0000000..99f6ae4 --- /dev/null +++ b/_types/common/PeriodicProcessor.d.ts @@ -0,0 +1,12 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +type PeriodicProcessorHost = NecessaryServices<"API" | "control", never>; +export declare class PeriodicProcessor { + _process: () => Promise; + _timer?: number; + _core: PeriodicProcessorHost; + constructor(core: PeriodicProcessorHost, process: () => Promise); + process(): Promise; + enable(interval: number): void; + disable(): void; +} +export {}; diff --git a/_types/common/SvelteItemView.d.ts b/_types/common/SvelteItemView.d.ts new file mode 100644 index 0000000..2baa17b --- /dev/null +++ b/_types/common/SvelteItemView.d.ts @@ -0,0 +1,9 @@ +import { ItemView } from "@/deps.ts"; +import { type mount } from "svelte"; +export declare abstract class SvelteItemView extends ItemView { + abstract instantiateComponent(target: HTMLElement): ReturnType | Promise>; + component?: ReturnType; + onOpen(): Promise; + _dismountComponent(): Promise; + onClose(): Promise; +} diff --git a/_types/common/events.d.ts b/_types/common/events.d.ts new file mode 100644 index 0000000..2ffd3aa --- /dev/null +++ b/_types/common/events.d.ts @@ -0,0 +1,36 @@ +import { eventHub } from "@lib/hub/hub"; +export declare const EVENT_PLUGIN_LOADED = "plugin-loaded"; +export declare const EVENT_PLUGIN_UNLOADED = "plugin-unloaded"; +export declare const EVENT_FILE_SAVED = "file-saved"; +export declare const EVENT_LEAF_ACTIVE_CHANGED = "leaf-active-changed"; +export declare const EVENT_REQUEST_OPEN_SETTINGS = "request-open-settings"; +export declare const EVENT_REQUEST_OPEN_SETTING_WIZARD = "request-open-setting-wizard"; +export declare const EVENT_REQUEST_OPEN_SETUP_URI = "request-open-setup-uri"; +export declare const EVENT_REQUEST_COPY_SETUP_URI = "request-copy-setup-uri"; +export declare const EVENT_REQUEST_SHOW_SETUP_QR = "request-show-setup-qr"; +export declare const EVENT_REQUEST_RELOAD_SETTING_TAB = "reload-setting-tab"; +export declare const EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG = "request-open-plugin-sync-dialog"; +export declare const EVENT_REQUEST_RUN_DOCTOR = "request-run-doctor"; +export declare const EVENT_REQUEST_RUN_FIX_INCOMPLETE = "request-run-fix-incomplete"; +export declare const EVENT_ANALYSE_DB_USAGE = "analyse-db-usage"; +export declare const EVENT_REQUEST_PERFORM_GC_V3 = "request-perform-gc-v3"; +declare global { + interface LSEvents { + [EVENT_PLUGIN_LOADED]: undefined; + [EVENT_PLUGIN_UNLOADED]: undefined; + [EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG]: undefined; + [EVENT_REQUEST_OPEN_SETTINGS]: undefined; + [EVENT_REQUEST_OPEN_SETTING_WIZARD]: undefined; + [EVENT_REQUEST_RELOAD_SETTING_TAB]: undefined; + [EVENT_LEAF_ACTIVE_CHANGED]: undefined; + [EVENT_REQUEST_OPEN_SETUP_URI]: undefined; + [EVENT_REQUEST_COPY_SETUP_URI]: undefined; + [EVENT_REQUEST_SHOW_SETUP_QR]: undefined; + [EVENT_REQUEST_RUN_DOCTOR]: string; + [EVENT_REQUEST_RUN_FIX_INCOMPLETE]: undefined; + [EVENT_ANALYSE_DB_USAGE]: undefined; + [EVENT_REQUEST_PERFORM_GC_V3]: undefined; + } +} +export * from "@lib/events/coreEvents.ts"; +export { eventHub }; diff --git a/_types/common/obsidianEvents.d.ts b/_types/common/obsidianEvents.d.ts new file mode 100644 index 0000000..7f57c79 --- /dev/null +++ b/_types/common/obsidianEvents.d.ts @@ -0,0 +1,14 @@ +import type { TFile } from "@/deps"; +import type { FilePathWithPrefix, LoadedEntry } from "@lib/common/models/db.type"; +export declare const EVENT_REQUEST_SHOW_HISTORY = "show-history"; +declare global { + interface LSEvents { + [EVENT_REQUEST_SHOW_HISTORY]: { + file: TFile; + fileOnDB: LoadedEntry; + } | { + file: FilePathWithPrefix; + fileOnDB: LoadedEntry; + }; + } +} diff --git a/_types/common/reportTool.d.ts b/_types/common/reportTool.d.ts new file mode 100644 index 0000000..90df840 --- /dev/null +++ b/_types/common/reportTool.d.ts @@ -0,0 +1,12 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; +export declare function generateReport(settings: ObsidianLiveSyncSettings, core: LiveSyncBaseCore): Promise<{ + obsidianInfo: { + navigator: string; + fileSystem: string; + }; + responseConfig: Record; + pluginConfig: ObsidianLiveSyncSettings; + manifestVersion: string; + packageVersion: string; +}>; diff --git a/_types/common/stores.d.ts b/_types/common/stores.d.ts new file mode 100644 index 0000000..1ed5321 --- /dev/null +++ b/_types/common/stores.d.ts @@ -0,0 +1,3 @@ +import { PersistentMap } from "octagonal-wheels/dataobject/PersistentMap"; +export declare let sameChangePairs: PersistentMap; +export declare function initializeStores(vaultName: string): void; diff --git a/_types/common/types.d.ts b/_types/common/types.d.ts new file mode 100644 index 0000000..bfa9858 --- /dev/null +++ b/_types/common/types.d.ts @@ -0,0 +1,47 @@ +import { type PluginManifest, TFile } from "@/deps.ts"; +import type { DatabaseEntry, FilePath } from "@lib/common/models/db.type"; +import type { EntryBody } from "@lib/common/models/db.definition"; +export type { CacheData, FileEventItem } from "@lib/common/types.ts"; +export interface PluginDataEntry extends DatabaseEntry { + deviceVaultName: string; + mtime: number; + manifest: PluginManifest; + mainJs: string; + manifestJson: string; + styleCss?: string; + dataJson?: string; + _conflicts?: string[]; + type: "plugin"; +} +export interface PluginList { + [key: string]: PluginDataEntry[]; +} +export interface DevicePluginList { + [key: string]: PluginDataEntry; +} +export declare const PERIODIC_PLUGIN_SWEEP = 60; +export interface InternalFileInfo { + path: FilePath; + mtime: number; + ctime: number; + size: number; + deleted?: boolean; +} +export interface FileInfo { + path: FilePath; + mtime: number; + ctime: number; + size: number; + deleted?: boolean; + file: TFile; +} +export type queueItem = { + entry: EntryBody; + missingChildren: string[]; + timeout?: number; + done?: boolean; + warned?: boolean; +}; +export declare const FileWatchEventQueueMax = 10; +export { configURIBase, configURIBaseQR } from "@lib/common/types.ts"; +export { CHeader, PSCHeader, PSCHeaderEnd, ICHeader, ICHeaderEnd, ICHeaderLength, ICXHeader, } from "@lib/common/models/fileaccess.const.ts"; diff --git a/_types/common/utils.d.ts b/_types/common/utils.d.ts new file mode 100644 index 0000000..b6dea00 --- /dev/null +++ b/_types/common/utils.d.ts @@ -0,0 +1,61 @@ +import { TAbstractFile } from "@/deps.ts"; +import type { AnyEntry, DocumentID, EntryHasPath, FilePath, FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { CouchDBCredentials } from "@lib/common/models/auth.type"; +import type { UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +export { ICHeader, ICXHeader } from "./types.ts"; +import type { KeyValueDatabase } from "@lib/interfaces/KeyValueDatabase.ts"; +export { scheduleTask, cancelTask, cancelAllTasks } from "octagonal-wheels/concurrency/task"; +export declare function path2id(filename: FilePathWithPrefix | FilePath, obfuscatePassphrase: string | false, caseInsensitive: boolean): Promise; +export declare function id2path(id: DocumentID, entry?: EntryHasPath): FilePathWithPrefix; +export declare function getPathFromTFile(file: TAbstractFile): FilePath; +import { isInternalFile, getPathFromUXFileInfo, getStoragePathFromUXFileInfo, getDatabasePathFromUXFileInfo } from "@lib/common/typeUtils.ts"; +export { isInternalFile, getPathFromUXFileInfo, getStoragePathFromUXFileInfo, getDatabasePathFromUXFileInfo }; +export declare function memoObject(key: string, obj: T): T; +export declare function memoIfNotExist(key: string, func: () => T | Promise): Promise; +export declare function retrieveMemoObject(key: string): T | false; +export declare function disposeMemoObject(key: string): void; +export declare function isValidPath(filename: string): boolean; +export declare function trimPrefix(target: string, prefix: string): string; +export { isInternalMetadata, id2InternalMetadataId, isChunk, isCustomisationSyncMetadata, isPluginMetadata, stripInternalMetadataPrefix, } from "@lib/common/typeUtils.ts"; +export declare const _requestToCouchDBFetch: (baseUri: string, username: string, password: string, path?: string, body?: unknown, method?: string) => Promise; +export declare const _requestToCouchDB: (baseUri: string, credentials: CouchDBCredentials, origin: string, path?: string, body?: unknown, method?: string, customHeaders?: Record) => Promise; +/** + * @deprecated Use requestToCouchDBWithCredentials instead. + */ +export declare const requestToCouchDB: (baseUri: string, username: string, password: string, origin?: string, key?: string, body?: string, method?: string, customHeaders?: Record) => Promise; +export declare function requestToCouchDBWithCredentials(baseUri: string, credentials: CouchDBCredentials, origin?: string, key?: string, body?: string, method?: string, customHeaders?: Record): Promise; +import { BASE_IS_NEW, EVEN, TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols.ts"; +export { BASE_IS_NEW, EVEN, TARGET_IS_NEW }; +import { compareMTime } from "@lib/common/utils.database.ts"; +export { compareMTime }; +export declare function markChangesAreSame(file: AnyEntry | string | UXFileInfoStub, mtime1: number, mtime2: number): true | undefined; +export declare function unmarkChanges(file: AnyEntry | string | UXFileInfoStub): void; +export declare function isMarkedAsSameChanges(file: UXFileInfoStub | AnyEntry | string, mtimes: number[]): typeof EVEN | undefined; +export declare function compareFileFreshness(baseFile: UXFileInfoStub | AnyEntry | undefined, checkTarget: UXFileInfo | AnyEntry | undefined): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; +export type MemoOption = { + key: string; + forceUpdate?: boolean; + validator?: (context: Map) => boolean; +}; +export declare function useMemo({ key, forceUpdate, validator }: MemoOption, updateFunc: (context: Map, prev: T) => T): T; +export declare function useStatic(key: string): { + value: T | undefined; +}; +export declare function useStatic(key: string, initial: T): { + value: T; +}; +export declare function disposeMemo(key: string): void; +export declare function disposeAllMemo(): void; +export declare function getLogLevel(showNotice: boolean): 32 | 64; +export type MapLike = { + set(key: K, value: V): Map; + clear(): void; + delete(key: K): boolean; + get(key: K): V | undefined; + has(key: K): boolean; + keys: () => IterableIterator; + get size(): number; +}; +export declare function autosaveCache(db: KeyValueDatabase, mapKey: string): Promise>; +export declare function onlyInNTimes(n: number, proc: (progress: number) => unknown): () => void; +export { displayRev } from "@lib/common/utils.ts"; diff --git a/_types/deps.d.ts b/_types/deps.d.ts new file mode 100644 index 0000000..dc1e1b0 --- /dev/null +++ b/_types/deps.d.ts @@ -0,0 +1,6 @@ +import type { FilePath } from "@lib/common/models/db.type"; +export { addIcon, App, debounce, Editor, FuzzySuggestModal, MarkdownRenderer, MarkdownView, Modal, Notice, Platform, Plugin, PluginSettingTab, requestUrl, sanitizeHTMLToDom, Setting, stringifyYaml, TAbstractFile, TextAreaComponent, TFile, TFolder, parseYaml, ItemView, WorkspaceLeaf, Menu, request, getLanguage, ButtonComponent, TextComponent, ToggleComponent, DropdownComponent, } from "obsidian"; +export type { DataWriteOptions, PluginManifest, RequestUrlParam, RequestUrlResponse, MarkdownFileInfo, ListedFiles, ValueComponent, Stat, } from "obsidian"; +declare const normalizePath: (from: T) => T; +export { normalizePath }; +export { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch"; diff --git a/_types/features/ConfigSync/CmdConfigSync.d.ts b/_types/features/ConfigSync/CmdConfigSync.d.ts new file mode 100644 index 0000000..3c2ab61 --- /dev/null +++ b/_types/features/ConfigSync/CmdConfigSync.d.ts @@ -0,0 +1,147 @@ +import { type PluginManifest, type App } from "@/deps.ts"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { LoadedEntry, FilePathWithPrefix, FilePath, AnyEntry } from "@lib/common/models/db.type"; +import { LiveSyncCommands } from "@/features/LiveSyncCommands.ts"; +import { PeriodicProcessor } from "@/common/PeriodicProcessor.ts"; +import { QueueProcessor } from "octagonal-wheels/concurrency/processor"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import type { PluginDialogModal } from "./PluginDialogModal.ts"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts"; +import type { LiveSyncCore } from "@/main.ts"; +declare global { + interface OPTIONAL_SYNC_FEATURES { + DISABLE: "DISABLE"; + CUSTOMIZE: "CUSTOMIZE"; + DISABLE_CUSTOM: "DISABLE_CUSTOM"; + } +} +export declare const pluginList: import("svelte/store").Writable; +export declare const pluginIsEnumerating: import("svelte/store").Writable; +export declare const pluginV2Progress: import("svelte/store").Writable; +export type PluginDataExFile = { + filename: string; + data: string[]; + mtime: number; + size: number; + version?: string; + hash?: string; + displayName?: string; +}; +export interface IPluginDataExDisplay { + documentPath: FilePathWithPrefix; + category: string; + name: string; + term: string; + displayName?: string; + files: (LoadedEntryPluginDataExFile | PluginDataExFile)[]; + version?: string; + mtime: number; +} +export type PluginDataExDisplay = { + documentPath: FilePathWithPrefix; + category: string; + name: string; + term: string; + displayName?: string; + files: PluginDataExFile[]; + version?: string; + mtime: number; +}; +type LoadedEntryPluginDataExFile = LoadedEntry & PluginDataExFile; +export declare const pluginManifests: Map; +export declare const pluginManifestStore: import("svelte/store").Writable>; +export declare class PluginDataExDisplayV2 { + documentPath: FilePathWithPrefix; + category: string; + term: string; + files: LoadedEntryPluginDataExFile[]; + name: string; + confKey: string; + constructor(data: IPluginDataExDisplay); + setFile(file: LoadedEntryPluginDataExFile): Promise; + deleteFile(filename: string): void; + _displayName: string | undefined; + _version: string | undefined; + applyLoadedManifest(): void; + get displayName(): string; + get version(): string | undefined; + get mtime(): number; +} +export type PluginDataEx = { + documentPath?: FilePathWithPrefix; + category: string; + name: string; + displayName?: string; + term: string; + files: PluginDataExFile[]; + version?: string; + mtime: number; +}; +export declare class ConfigSync extends LiveSyncCommands { + pluginDialogClass: new (app: App, plugin: ObsidianLiveSyncPlugin) => PluginDialogModal; + constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore, pluginDialogClass: new (app: App, plugin: ObsidianLiveSyncPlugin) => PluginDialogModal); + get configDir(): string; + get kvDB(): import("../../lib/src/interfaces/KeyValueDatabase.ts").KeyValueDatabase; + get useV2(): boolean; + get useSyncPluginEtc(): boolean; + isThisModuleEnabled(): boolean; + pluginDialog?: PluginDialogModal; + periodicPluginSweepProcessor: PeriodicProcessor; + pluginList: IPluginDataExDisplay[]; + showPluginSyncModal(): void; + hidePluginSyncModal(): void; + onunload(): void; + addRibbonIcon: (icon: string, title: string, callback: (evt: MouseEvent) => any) => HTMLElement; + onload(): void; + getFileCategory(filePath: string): "CONFIG" | "THEME" | "SNIPPET" | "PLUGIN_MAIN" | "PLUGIN_ETC" | "PLUGIN_DATA" | ""; + isTargetPath(filePath: string): boolean; + private _everyOnDatabaseInitialized; + _everyBeforeReplicate(showNotice: boolean): Promise; + _everyOnResumeProcess(): Promise; + _everyAfterResumeProcess(): Promise; + reloadPluginList(showMessage: boolean): Promise; + loadPluginData(path: FilePathWithPrefix): Promise; + pluginScanProcessor: QueueProcessor; + pluginScanProcessorV2: QueueProcessor; + filenameToUnifiedKey(path: string, termOverRide?: string): FilePathWithPrefix; + filenameWithUnifiedKey(path: string, termOverRide?: string): FilePathWithPrefix; + unifiedKeyPrefixOfTerminal(termOverRide?: string): FilePathWithPrefix; + parseUnifiedPath(unifiedPath: FilePathWithPrefix): { + category: string; + device: string; + key: string; + filename: string; + pathV1: FilePathWithPrefix; + }; + loadedManifest_mTime: Map; + createPluginDataExFileV2(unifiedPathV2: FilePathWithPrefix, loaded?: LoadedEntry): Promise; + createPluginDataFromV2(unifiedPathV2: FilePathWithPrefix): PluginDataExDisplayV2 | undefined; + updatingV2Count: number; + updatePluginListV2(showMessage: boolean, unifiedFilenameWithKey: FilePathWithPrefix): Promise; + migrateV1ToV2(showMessage: boolean, entry: AnyEntry): Promise; + updatePluginList(showMessage: boolean, updatedDocumentPath?: FilePathWithPrefix): Promise; + compareUsingDisplayData(dataA: IPluginDataExDisplay, dataB: IPluginDataExDisplay, compareEach?: boolean): Promise; + applyDataV2(data: PluginDataExDisplayV2, content?: string): Promise; + applyData(data: IPluginDataExDisplay, content?: string): Promise; + deleteData(data: PluginDataEx): Promise; + _anyModuleParsedReplicationResultItem(docs: PouchDB.Core.ExistingDocument): Promise; + _everyRealizeSettingSyncMode(): Promise; + recentProcessedInternalFiles: string[]; + makeEntryFromFile(path: FilePath): Promise; + storeCustomisationFileV2(path: FilePath, term: string, force?: boolean): Promise; + storeCustomizationFiles(path: FilePath, termOverRide?: string): Promise; + _anyProcessOptionalFileEvent(path: FilePath): Promise; + watchVaultRawEventsAsync(path: FilePath): Promise; + scanAllConfigFiles(showMessage: boolean): Promise; + deleteConfigOnDatabase(prefixedFileName: FilePathWithPrefix, forceWrite?: boolean): Promise; + scanInternalFiles(): Promise; + private _allAskUsingOptionalSyncFeature; + private __askHiddenFileConfiguration; + _anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise; + private _allSuspendExtraSync; + private _allConfigureOptionalSyncFeature; + configureHiddenFileSync(mode: keyof OPTIONAL_SYNC_FEATURES): Promise; + getFiles(path: string, lastDepth: number): Promise; + onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void; +} +export {}; diff --git a/_types/features/ConfigSync/PluginDialogModal.d.ts b/_types/features/ConfigSync/PluginDialogModal.d.ts new file mode 100644 index 0000000..c75f754 --- /dev/null +++ b/_types/features/ConfigSync/PluginDialogModal.d.ts @@ -0,0 +1,11 @@ +import { mount } from "svelte"; +import { App, Modal } from "@/deps.ts"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +export declare class PluginDialogModal extends Modal { + plugin: ObsidianLiveSyncPlugin; + component: ReturnType | undefined; + isOpened(): boolean; + constructor(app: App, plugin: ObsidianLiveSyncPlugin); + onOpen(): void; + onClose(): void; +} diff --git a/_types/features/HiddenFileCommon/JsonResolveModal.d.ts b/_types/features/HiddenFileCommon/JsonResolveModal.d.ts new file mode 100644 index 0000000..b07a03d --- /dev/null +++ b/_types/features/HiddenFileCommon/JsonResolveModal.d.ts @@ -0,0 +1,19 @@ +import { App, Modal } from "@/deps.ts"; +import type { FilePath, LoadedEntry } from "@lib/common/models/db.type"; +import { mount } from "svelte"; +export declare class JsonResolveModal extends Modal { + filename: FilePath; + callback?: (keepRev?: string, mergedStr?: string) => Promise; + docs: LoadedEntry[]; + component?: ReturnType; + nameA: string; + nameB: string; + defaultSelect: string; + keepOrder: boolean; + hideLocal: boolean; + title: string; + constructor(app: App, filename: FilePath, docs: LoadedEntry[], callback: (keepRev?: string, mergedStr?: string) => Promise, nameA?: string, nameB?: string, defaultSelect?: string, keepOrder?: boolean, hideLocal?: boolean, title?: string); + UICallback(keepRev?: string, mergedStr?: string): Promise; + onOpen(): void; + onClose(): void; +} diff --git a/_types/features/HiddenFileSync/CmdHiddenFileSync.d.ts b/_types/features/HiddenFileSync/CmdHiddenFileSync.d.ts new file mode 100644 index 0000000..738ef4a --- /dev/null +++ b/_types/features/HiddenFileSync/CmdHiddenFileSync.d.ts @@ -0,0 +1,153 @@ +import type { LoadedEntry, FilePathWithPrefix, FilePath, DocumentID, MetaEntry } from "@lib/common/models/db.type"; +import type { UXFileInfo, UXStat, UXDataWriteOptions } from "@lib/common/models/fileaccess.type"; +import { type InternalFileInfo } from "@/common/types.ts"; +import type { CustomRegExp } from "@lib/common/utils.regexp.ts"; +import { type MapLike } from "@/common/utils.ts"; +import { PeriodicProcessor } from "@/common/PeriodicProcessor.ts"; +import { LiveSyncCommands } from "@/features/LiveSyncCommands.ts"; +import { QueueProcessor } from "octagonal-wheels/concurrency/processor"; +import type { LiveSyncCore } from "@/main.ts"; +type SyncDirection = "push" | "pull" | "safe" | "pullForce" | "pushForce"; +declare global { + interface OPTIONAL_SYNC_FEATURES { + FETCH: "FETCH"; + OVERWRITE: "OVERWRITE"; + MERGE: "MERGE"; + DISABLE: "DISABLE"; + DISABLE_HIDDEN: "DISABLE_HIDDEN"; + } +} +export declare class HiddenFileSync extends LiveSyncCommands { + isThisModuleEnabled(): boolean; + periodicInternalFileScanProcessor: PeriodicProcessor; + get kvDB(): import("../../lib/src/interfaces/KeyValueDatabase").KeyValueDatabase; + getConflictedDoc(path: FilePathWithPrefix, rev: string): Promise; + onunload(): void; + onload(): void; + private _everyOnDatabaseInitialized; + _everyBeforeReplicate(showNotice: boolean): Promise; + private _everyOnloadAfterLoadSettings; + updateSettingCache(): void; + isReady(): boolean; + performStartupScan(showNotice: boolean): Promise; + _everyOnResumeProcess(): Promise; + _everyRealizeSettingSyncMode(): Promise; + _anyProcessOptionalFileEvent(path: FilePath): Promise; + _anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise; + _anyProcessOptionalSyncFiles(doc: LoadedEntry): Promise; + loadFileWithInfo(path: FilePath): Promise; + _fileInfoLastProcessed: MapLike; + _fileInfoLastKnown: MapLike; + _databaseInfoLastProcessed: MapLike; + statToKey(stat: UXStat | null): string; + docToKey(doc: LoadedEntry | MetaEntry): string; + fileToStatKey(file: FilePath, stat?: UXStat | null): Promise; + updateLastProcessedFile(file: FilePath, keySrc: string | UXStat): void; + updateLastProcessedAsActualFile(file: FilePath, stat?: UXStat | null): Promise; + resetLastProcessedFile(targetFiles: FilePath[] | false): void; + getLastProcessedFileMTime(file: FilePath): number; + getLastProcessedFileKey(file: FilePath): string | undefined; + getLastProcessedDatabaseKey(file: FilePath): string | undefined; + updateLastProcessedDatabase(file: FilePath, keySrc: string | MetaEntry | LoadedEntry): void; + updateLastProcessed(path: FilePath, db: MetaEntry | LoadedEntry, stat: UXStat): void; + updateLastProcessedDeletion(path: FilePath, db: MetaEntry | LoadedEntry | false): void; + ensureDir(path: FilePath): Promise; + writeFile(path: FilePath, data: string | ArrayBuffer, opt?: UXDataWriteOptions): Promise; + __removeFile(path: FilePath): Promise<"OK" | "ALREADY" | false>; + triggerEvent(path: FilePath): Promise; + updateLastProcessedAsActualDatabase(file: FilePath, doc?: MetaEntry | LoadedEntry | null | false): Promise; + resetLastProcessedDatabase(targetFiles: FilePath[] | false): void; + adoptCurrentStorageFilesAsProcessed(targetFiles: FilePath[] | false): Promise; + adoptCurrentDatabaseFilesAsProcessed(targetFiles: FilePath[] | false): Promise; + semaphore: import("octagonal-wheels/concurrency/semaphore_v2").SemaphoreObject; + serializedForEvent(file: FilePath, fn: () => Promise): Promise; + useStorageFiles(files: FilePath[], showNotice?: boolean, onlyNew?: boolean): Promise; + trackScannedStorageChanges(processFiles: FilePath[], showNotice?: boolean, onlyNew?: boolean, forceWriteAll?: boolean, includeDeleted?: boolean): Promise; + scanAllStorageChanges(showNotice?: boolean, onlyNew?: boolean, forceWriteAll?: boolean, includeDeleted?: boolean): Promise; + /** + * check the file is changed or not, and if changed, process it. + */ + trackStorageFileModification(path: FilePath, onlyNew?: boolean, forceWrite?: boolean, includeDeleted?: boolean): Promise; + pendingConflictChecks: Set; + queueConflictCheck(path: FilePathWithPrefix): void; + finishConflictCheck(path: FilePathWithPrefix): void; + requeueConflictCheck(path: FilePathWithPrefix): void; + resolveConflictOnInternalFiles(): Promise; + resolveByNewerEntry(id: DocumentID, path: FilePathWithPrefix, currentDoc: MetaEntry, currentRev: string, conflictedRev: string): Promise; + conflictResolutionProcessor: QueueProcessor; + showJSONMergeDialogAndMerge(docA: LoadedEntry, docB: LoadedEntry): Promise; + getDocProps(doc: LoadedEntry): { + id: DocumentID; + rev: string | undefined; + revDisplay: string; + prefixedPath: FilePathWithPrefix; + path: FilePath; + isDeleted: boolean; + shortenedId: string; + shortenedPath: string; + }; + processReplicationResult(doc: LoadedEntry): Promise; + cacheFileRegExps: Map; + /** + * Parses the regular expression settings for hidden file synchronization. + * @returns An object containing the ignore and target filters. + */ + parseRegExpSettings(): { + ignoreFilter: CustomRegExp[]; + targetFilter: CustomRegExp[]; + }; + /** + * Checks if the target file path matches the defined patterns. + */ + isTargetFileInPatterns(path: string): boolean; + cacheCustomisationSyncIgnoredFiles: Map; + /** + * Gets the list of files ignored for customization synchronization. + * @returns An array of ignored file paths (lowercase). + */ + getCustomisationSynchronizationIgnoredFiles(): string[]; + /** + * Checks if the given path is not ignored by customization synchronization. + * @param path The file path to check. + * @returns True if the path is not ignored; otherwise, false. + */ + isNotIgnoredByCustomisationSync(path: string): boolean; + isHiddenFileSyncHandlingPath(path: FilePath): boolean; + isTargetFile(path: FilePath): Promise; + trackScannedDatabaseChange(processFiles: MetaEntry[], showNotice?: boolean, onlyNew?: boolean, forceWriteAll?: boolean, includeDeletion?: boolean): Promise; + applyOfflineChanges(showNotice: boolean): Promise; + scanAllDatabaseChanges(showNotice?: boolean, onlyNew?: boolean, forceWriteAll?: boolean, includeDeletion?: boolean): Promise; + useDatabaseFiles(files: MetaEntry[], showNotice?: boolean, onlyNew?: boolean): Promise; + trackDatabaseFileModification(path: FilePath, headerLine: string, preventDoubleProcess?: boolean, onlyNew?: boolean, meta?: MetaEntry | false, includeDeletion?: boolean): Promise; + queuedNotificationFiles: Set; + notifyConfigChange(): void; + queueNotification(key: FilePath): void; + rebuildMerging(showNotice: boolean, targetFiles?: FilePath[] | false): Promise; + rebuildFromStorage(showNotice: boolean, targetFiles?: FilePath[] | false, onlyNew?: boolean): Promise; + getAllDatabaseFiles(): Promise; + rebuildFromDatabase(showNotice: boolean, targetFiles?: FilePath[] | false, onlyNew?: boolean): Promise; + initialiseInternalFileSync(direction: SyncDirection, showMessage: boolean, targetFilesSrc?: string[] | false): Promise; + __loadBaseSaveData(file: FilePath, includeContent?: boolean): Promise; + storeInternalFileToDatabase(file: InternalFileInfo | UXFileInfo, forceWrite?: boolean): Promise; + deleteInternalFileOnDatabase(filenameSrc: FilePath, forceWrite?: boolean): Promise; + extractInternalFileFromDatabase(storageFilePath: FilePath, force?: boolean, metaEntry?: MetaEntry | LoadedEntry, preventDoubleProcess?: boolean, onlyNew?: boolean, includeDeletion?: boolean): Promise; + __checkIsNeedToWriteFile(storageFilePath: FilePath, content: string | ArrayBuffer): Promise; + __writeFile(storageFilePath: FilePath, fileOnDB: LoadedEntry, force: boolean): Promise; + __deleteFile(storageFilePath: FilePath): Promise; + private _allAskUsingOptionalSyncFeature; + private __askHiddenFileConfiguration; + private _allSuspendExtraSync; + private _allConfigureOptionalSyncFeature; + configureHiddenFileSync(mode: keyof OPTIONAL_SYNC_FEATURES): Promise; + scanInternalFileNames(): Promise; + scanInternalFiles(): Promise; + getFiles(path: string, checkFunction: (path: FilePath) => Promise | boolean): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} +export {}; diff --git a/_types/features/LiveSyncCommands.d.ts b/_types/features/LiveSyncCommands.d.ts new file mode 100644 index 0000000..ffea3b2 --- /dev/null +++ b/_types/features/LiveSyncCommands.d.ts @@ -0,0 +1,35 @@ +import type { AnyEntry, DocumentID, FilePath, FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { LOG_LEVEL } from "@lib/common/logger"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import type { LiveSyncCore } from "@/main.ts"; +import { createInstanceLogFunction } from "@lib/services/lib/logUtils.ts"; +export declare abstract class LiveSyncCommands { + /** + * @deprecated This class is deprecated. Please use core + */ + plugin: ObsidianLiveSyncPlugin; + core: LiveSyncCore; + get app(): import("obsidian").App; + get settings(): import("../lib/src/common/types").ObsidianLiveSyncSettings; + get localDatabase(): import("../lib/src/pouchdb/LiveSyncLocalDB").LiveSyncLocalDB; + get services(): import("../lib/src/services/InjectableServices").InjectableServiceHub; + path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise; + getPath(entry: AnyEntry): FilePathWithPrefix; + constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore); + abstract onunload(): void; + abstract onload(): void | Promise; + _isMainReady(): boolean; + _isMainSuspended(): boolean; + _isDatabaseReady(): boolean; + _log: ReturnType; + _verbose: (msg: unknown, key?: string) => void; + _info: (msg: unknown, key?: string) => void; + _notice: (msg: unknown, key?: string) => void; + _progress: (prefix?: string, level?: LOG_LEVEL) => { + log: (msg: unknown) => void; + once: (msg: unknown) => void; + done: (msg?: string) => void; + }; + _debug: (msg: unknown, key?: string) => void; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.d.ts b/_types/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.d.ts new file mode 100644 index 0000000..7a5bb1b --- /dev/null +++ b/_types/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.d.ts @@ -0,0 +1,58 @@ +import type { DocumentID, EntryLeaf } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import { LiveSyncCommands } from "@/features/LiveSyncCommands"; +type ChunkID = DocumentID; +type NoteDocumentID = DocumentID; +type Rev = string; +type ChunkUsageMap = Map>>; +export declare class LocalDatabaseMaintenance extends LiveSyncCommands { + onunload(): void; + onload(): void | Promise; + allChunks(includeDeleted?: boolean): Promise<{ + used: Set; + existing: Map; + }>; + get database(): PouchDB.Database; + clearHash(): void; + confirm(title: string, message: string, affirmative?: string, negative?: string): Promise; + isAvailable(): boolean; + /** + * Resurrect deleted chunks that are still used in the database. + */ + resurrectChunks(): Promise; + /** + * Commit deletion of files that are marked as deleted. + * This method makes the deletion permanent, and the files will not be recovered. + * After this, chunks that are used in the deleted files become ready for compaction. + */ + commitFileDeletion(): Promise; + /** + * Commit deletion of chunks that are not used in the database. + * This method makes the deletion permanent, and the chunks will not be recovered if the database run compaction. + * After this, the database can shrink the database size by compaction. + * It is recommended to compact the database after this operation (History should be kept once before compaction). + */ + commitChunkDeletion(): Promise; + /** + * Compact the database. + * This method removes all deleted chunks that are not used in the database. + * Make sure all devices are synchronized before running this method. + */ + markUnusedChunks(): Promise; + removeUnusedChunks(): Promise; + scanUnusedChunks(): Promise<{ + chunkSet: Set; + chunkUsageMap: ChunkUsageMap; + unusedSet: Set; + }>; + /** + * Track changes in the database and update the chunk usage map for garbage collection. + * Note that this only able to perform without Fetch chunks on demand. + */ + trackChanges(fromStart?: boolean, showNotice?: boolean): Promise; + performGC(showingNotice?: boolean): Promise; + analyseDatabase(): Promise; + compactDatabase(): Promise; + gcv3(): Promise; +} +export {}; diff --git a/_types/features/P2PSync/P2PReplicator/P2POpenReplicationModal.d.ts b/_types/features/P2PSync/P2PReplicator/P2POpenReplicationModal.d.ts new file mode 100644 index 0000000..f72d911 --- /dev/null +++ b/_types/features/P2PSync/P2PReplicator/P2POpenReplicationModal.d.ts @@ -0,0 +1,21 @@ +import { App, Modal } from "@/deps.ts"; +import { mount } from "svelte"; +import type { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator"; +export type P2POpenReplicationModalCallback = { + onSync: (peerId: string) => Promise; + onSyncAndClose: (peerId: string) => Promise; +}; +export declare class P2POpenReplicationModal extends Modal { + liveSyncReplicator: LiveSyncTrysteroReplicator; + callback?: P2POpenReplicationModalCallback; + component?: ReturnType; + showResult: boolean; + title: string; + onClosed?: () => void; + rebuildMode: boolean; + constructor(app: App, liveSyncReplicator: LiveSyncTrysteroReplicator, callback?: P2POpenReplicationModalCallback, showResult?: boolean, title?: string, onClosed?: () => void, rebuildMode?: boolean); + onSync(peerId: string): Promise; + onSyncAndClose(peerId: string): Promise; + onOpen(): void; + onClose(): void; +} diff --git a/_types/features/P2PSync/P2PReplicator/P2PReplicationUI.d.ts b/_types/features/P2PSync/P2PReplicator/P2PReplicationUI.d.ts new file mode 100644 index 0000000..63b1776 --- /dev/null +++ b/_types/features/P2PSync/P2PReplicator/P2PReplicationUI.d.ts @@ -0,0 +1,22 @@ +import { App } from "@/deps.ts"; +import type { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator"; +/** + * Creates an openReplicationUI factory for Obsidian environments. + * Returns a per-replicator closure that opens the P2P Replication modal + * and performs bidirectional sync (pull then push on success). + * + * Usage: + * const factory = createOpenReplicationUI(app); + * useP2PReplicatorFeature(core, factory); + */ +export declare function createOpenReplicationUI(app: App): (replicator: LiveSyncTrysteroReplicator) => (showResult: boolean) => Promise; +/** + * Creates an openRebuildUI factory for Obsidian environments. + * Opens the P2P Replication modal in "rebuild" mode — one-way pull only, + * with setOnSetup / clearOnSetup bracketing the replicateFrom call. + * + * Usage: + * const factory = createOpenRebuildUI(app); + * useP2PReplicatorFeature(core, createOpenReplicationUI(app), factory); + */ +export declare function createOpenRebuildUI(app: App): (replicator: LiveSyncTrysteroReplicator) => (showResult: boolean) => Promise; diff --git a/_types/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.d.ts b/_types/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.d.ts new file mode 100644 index 0000000..762c664 --- /dev/null +++ b/_types/features/P2PSync/P2PReplicator/P2PReplicatorPaneView.d.ts @@ -0,0 +1,28 @@ +import { Menu, WorkspaceLeaf } from "@/deps.ts"; +import { SvelteItemView } from "@/common/SvelteItemView.ts"; +import { type PeerStatus } from "@lib/replication/trystero/P2PReplicatorPaneCommon.ts"; +import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts"; +import type { P2PPaneParams } from "@lib/replication/trystero/UseP2PReplicatorResult"; +export declare const VIEW_TYPE_P2P = "p2p-replicator"; +export declare class P2PReplicatorPaneView extends SvelteItemView { + core: LiveSyncBaseCore; + private _p2pResult; + icon: string; + title: string; + navigation: boolean; + getIcon(): string; + get replicator(): import("../../../lib/src/replication/trystero/LiveSyncTrysteroReplicator").LiveSyncTrysteroReplicator; + replicateFrom(peer: PeerStatus): Promise; + replicateTo(peer: PeerStatus): Promise; + getRemoteConfig(peer: PeerStatus): Promise; + toggleProp(peer: PeerStatus, prop: "syncOnConnect" | "watchOnConnect" | "syncOnReplicationCommand"): Promise; + m?: Menu; + constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2pResult: P2PPaneParams); + getViewType(): string; + getDisplayText(): string; + onClose(): Promise; + instantiateComponent(target: HTMLElement): { + $on?(type: string, callback: (e: any) => void): () => void; + $set?(props: Partial>): void; + } & Record; +} diff --git a/_types/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.d.ts b/_types/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.d.ts new file mode 100644 index 0000000..f7296e2 --- /dev/null +++ b/_types/features/P2PSync/P2PReplicator/P2PServerStatusPaneView.d.ts @@ -0,0 +1,19 @@ +import { WorkspaceLeaf } from "@/deps.ts"; +import { SvelteItemView } from "@/common/SvelteItemView.ts"; +import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts"; +import type { P2PPaneParams } from "@lib/replication/trystero/UseP2PReplicatorResult"; +export declare const VIEW_TYPE_P2P_SERVER_STATUS = "p2p-server-status"; +export declare class P2PServerStatusPaneView extends SvelteItemView { + core: LiveSyncBaseCore; + private _p2pResult; + icon: string; + navigation: boolean; + constructor(leaf: WorkspaceLeaf, core: LiveSyncBaseCore, p2pResult: P2PPaneParams); + getIcon(): string; + getViewType(): string; + getDisplayText(): string; + instantiateComponent(target: HTMLElement): { + $on?(type: string, callback: (e: any) => void): () => void; + $set?(props: Partial>): void; + } & Record; +} diff --git a/_types/lib/_tools/bakei18n.d.ts b/_types/lib/_tools/bakei18n.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/_tools/bakei18n.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/_tools/checkI18nCoverage.d.ts b/_types/lib/_tools/checkI18nCoverage.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/_tools/checkI18nCoverage.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/_tools/decompileRosetta.d.ts b/_types/lib/_tools/decompileRosetta.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/_tools/decompileRosetta.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/_tools/decompileRosettaToJson.d.ts b/_types/lib/_tools/decompileRosettaToJson.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/_tools/decompileRosettaToJson.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/_tools/json2yaml.d.ts b/_types/lib/_tools/json2yaml.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/_tools/json2yaml.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/_tools/messagelib.d.ts b/_types/lib/_tools/messagelib.d.ts new file mode 100644 index 0000000..c064044 --- /dev/null +++ b/_types/lib/_tools/messagelib.d.ts @@ -0,0 +1,2 @@ +export declare function objectToDotted(obj: any, prefix?: string): Record; +export declare function dottedToObject(obj: Record): Record; diff --git a/_types/lib/_tools/yaml2json.d.ts b/_types/lib/_tools/yaml2json.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/_tools/yaml2json.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/src/API/DirectFileManipulator.d.ts b/_types/lib/src/API/DirectFileManipulator.d.ts new file mode 100644 index 0000000..67b9d96 --- /dev/null +++ b/_types/lib/src/API/DirectFileManipulator.d.ts @@ -0,0 +1,2 @@ +export { DirectFileManipulator } from "./DirectFileManipulatorV2.ts"; +export type { DirectFileManipulatorOptions } from "./DirectFileManipulatorV2.ts"; diff --git a/_types/lib/src/API/processSetting.d.ts b/_types/lib/src/API/processSetting.d.ts new file mode 100644 index 0000000..3318631 --- /dev/null +++ b/_types/lib/src/API/processSetting.d.ts @@ -0,0 +1,41 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +/** + * Encode settings to a tiny array to encode in QRCode, + * Due to size limitation of QR code, we encode settings as an array instead of object. + * @param settings settings to encode + */ +export declare function encodeSettingsToQRCodeData(settings: ObsidianLiveSyncSettings): string; +/** + * Decode settings from QR code data string + * @param qr data string from QR code + * @returns Decoded settings + */ +export declare function decodeSettingsFromQRCodeData(qr: string): ObsidianLiveSyncSettings; +export declare const enum OutputFormat { + SVG = 0, + ASCII = 1 +} +export interface SplitQRCodeData { + total: number; + parts: string[]; +} +/** + * Encode setting string to QR code in specified format + * @param settingString Setting string to encode + * @param format Output format + */ +export declare function encodeQR(settingString: string, format: OutputFormat): string | SplitQRCodeData; +type ErasureProperties = keyof ObsidianLiveSyncSettings; +/** + * Generate setup URI with encrypted settings + * @param settingString Settings to encode + * @param passphrase Passphrase to encrypt the settings + * @param removeProperties Properties to remove from the settings + * Means these properties will not be included in the generated setup URI, + * See also necessaryErasureProperties for properties that will always be removed. + * @param skipDefaultValue Whether to skip default values + * @returns Generated setup URI + */ +export declare function encodeSettingsToSetupURI(settingString: ObsidianLiveSyncSettings, passphrase: string, removeProperties?: ErasureProperties[], skipDefaultValue?: boolean): Promise; +export declare function decodeSettingsFromSetupURI(uri: string, passphrase: string): Promise; +export {}; diff --git a/_types/lib/src/ContentSplitter/ContentSplitter.d.ts b/_types/lib/src/ContentSplitter/ContentSplitter.d.ts new file mode 100644 index 0000000..5a79b69 --- /dev/null +++ b/_types/lib/src/ContentSplitter/ContentSplitter.d.ts @@ -0,0 +1,24 @@ +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { ISettingService } from "@lib/services/base/IService.ts"; +/** + * ContentSplitter interface for splitting content into chunks. + */ +export type SplitOptions = { + blob: Blob; + path: FilePathWithPrefix; + pieceSize: number; + plainSplit: boolean; + minimumChunkSize: number; + useWorker: boolean; + useSegmenter: boolean; +}; +/** + * The maximum size, in bytes, of a document to be processed by the content splitter in the foreground. + */ +export declare const MAX_CHUNKS_SIZE_ON_UI = 1024; +/** + * Options for the content splitter. + */ +export type ContentSplitterOptions = { + settingService: ISettingService; +}; diff --git a/_types/lib/src/ContentSplitter/ContentSplitterBase.d.ts b/_types/lib/src/ContentSplitter/ContentSplitterBase.d.ts new file mode 100644 index 0000000..9487b1e --- /dev/null +++ b/_types/lib/src/ContentSplitter/ContentSplitterBase.d.ts @@ -0,0 +1,51 @@ +import type { SavingEntry } from "@lib/common/models/db.type"; +import { type ContentSplitterOptions, type SplitOptions } from "./ContentSplitter.ts"; +export declare abstract class ContentSplitterCore { + /** + * Options for the content splitter. + * These settings include the chunk splitter version and other configurations. + */ + options: ContentSplitterOptions; + /** + * Task for initialising the content splitter. + * This ensures that the splitter is initialised before any operations are performed. + */ + initialised: Promise | undefined; + /** + * Constructor for the content splitter core. + * @param params Content splitter options + */ + constructor(params: ContentSplitterOptions); + /** + * Initialise the content splitter with the provided options. + * @param options Content splitter options + */ + abstract initialise(options: ContentSplitterOptions): Promise; + /** + * Split the content of the loaded entry into chunks. + * @param entry The loaded entry to be split into chunks + */ + abstract splitContent(entry: SavingEntry): Promise | Generator>; +} +export declare abstract class ContentSplitterBase extends ContentSplitterCore { + initialise(_options: ContentSplitterOptions): Promise; + /** + * Check whether the content splitter is available for the given settings. + * @param setting Content splitter options + * @returns True if the content splitter is available; false otherwise + */ + static isAvailableFor(setting: ContentSplitterOptions): boolean; + /** + * Process the content and split it into chunks. + * @param options Blob content to be split into chunks + */ + abstract processSplit(options: SplitOptions): Promise | Generator>; + getParamsFor(entry: SavingEntry): SplitOptions; + /** + * Split the content of the loaded entry into chunks. + * This method waits for the initialisation task to complete before proceeding. + * @param entry The loaded entry to be split into chunks + * @returns A generator that yields the split chunks + */ + splitContent(entry: SavingEntry): Promise | Generator>; +} diff --git a/_types/lib/src/ContentSplitter/ContentSplitterRabinKarp.d.ts b/_types/lib/src/ContentSplitter/ContentSplitterRabinKarp.d.ts new file mode 100644 index 0000000..430a10f --- /dev/null +++ b/_types/lib/src/ContentSplitter/ContentSplitterRabinKarp.d.ts @@ -0,0 +1,9 @@ +import type { ContentSplitterOptions, SplitOptions } from "./ContentSplitter.ts"; +import { ContentSplitterBase } from "./ContentSplitterBase.ts"; +/** + * Rabin-Karp content splitter for efficient chunking + */ +export declare class ContentSplitterRabinKarp extends ContentSplitterBase { + static isAvailableFor(setting: ContentSplitterOptions): boolean; + processSplit(options: SplitOptions): Promise | Generator>; +} diff --git a/_types/lib/src/ContentSplitter/ContentSplitterV1.d.ts b/_types/lib/src/ContentSplitter/ContentSplitterV1.d.ts new file mode 100644 index 0000000..946254e --- /dev/null +++ b/_types/lib/src/ContentSplitter/ContentSplitterV1.d.ts @@ -0,0 +1,9 @@ +import type { ContentSplitterOptions, SplitOptions } from "./ContentSplitter"; +import { ContentSplitterBase } from "./ContentSplitterBase"; +/** + * Legacy content splitter for version 1. + */ +export declare class ContentSplitterV1 extends ContentSplitterBase { + static isAvailableFor(setting: ContentSplitterOptions): boolean; + processSplit(options: SplitOptions): Promise | Generator>; +} diff --git a/_types/lib/src/ContentSplitter/ContentSplitterV2.d.ts b/_types/lib/src/ContentSplitter/ContentSplitterV2.d.ts new file mode 100644 index 0000000..232ea91 --- /dev/null +++ b/_types/lib/src/ContentSplitter/ContentSplitterV2.d.ts @@ -0,0 +1,9 @@ +import type { ContentSplitterOptions, SplitOptions } from "./ContentSplitter.ts"; +import { ContentSplitterBase } from "./ContentSplitterBase.ts"; +/** + * Content splitter for version 2, which supports segmenter-based splitting. + */ +export declare class ContentSplitterV2 extends ContentSplitterBase { + static isAvailableFor(setting: ContentSplitterOptions): boolean; + processSplit(options: SplitOptions): Promise | Generator>; +} diff --git a/_types/lib/src/ContentSplitter/ContentSplitters.d.ts b/_types/lib/src/ContentSplitter/ContentSplitters.d.ts new file mode 100644 index 0000000..ba013c5 --- /dev/null +++ b/_types/lib/src/ContentSplitter/ContentSplitters.d.ts @@ -0,0 +1,12 @@ +import type { SavingEntry } from "@lib/common/models/db.type"; +import type { ContentSplitterOptions } from "./ContentSplitter"; +import { ContentSplitterCore, type ContentSplitterBase } from "./ContentSplitterBase"; +/** + * ContentSplitter class that manages the active content splitter based on the provided settings. + */ +export declare class ContentSplitter extends ContentSplitterCore { + _activeSplitter: ContentSplitterBase; + constructor(options: ContentSplitterOptions); + initialise(options: ContentSplitterOptions): Promise; + splitContent(entry: SavingEntry): Promise | Generator>; +} diff --git a/_types/lib/src/UI/svelteDialog.d.ts b/_types/lib/src/UI/svelteDialog.d.ts new file mode 100644 index 0000000..0f2def9 --- /dev/null +++ b/_types/lib/src/UI/svelteDialog.d.ts @@ -0,0 +1,2 @@ +export type { HasSetResult, HasGetInitialData, ComponentHasResult, GuestDialogProps, DialogSvelteComponentBaseProps, DialogControlBase, } from "@lib/services/implements/base/SvelteDialog.ts"; +export { CONTEXT_DIALOG_CONTROLS, setupDialogContext, getDialogContext, SvelteDialogManagerBase, } from "@lib/services/implements/base/SvelteDialog.ts"; diff --git a/_types/lib/src/bureau/bureau.d.ts b/_types/lib/src/bureau/bureau.d.ts new file mode 100644 index 0000000..fcf7307 --- /dev/null +++ b/_types/lib/src/bureau/bureau.d.ts @@ -0,0 +1,7 @@ +import { type SlipBoard } from "octagonal-wheels/bureau/SlipBoard"; +declare global { + interface Slips extends LSSlips { + _dummy: undefined; + } +} +export declare const globalSlipBoard: SlipBoard; diff --git a/_types/lib/src/cli/APITest.sample.d.ts b/_types/lib/src/cli/APITest.sample.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/src/cli/APITest.sample.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/src/common/ConnectionString.d.ts b/_types/lib/src/common/ConnectionString.d.ts new file mode 100644 index 0000000..2bd83c6 --- /dev/null +++ b/_types/lib/src/common/ConnectionString.d.ts @@ -0,0 +1,30 @@ +import type { CouchDBConnection, BucketSyncSetting, P2PConnectionInfo } from "./models/setting.type"; +export type RemoteConfigurationResult = { + type: "couchdb"; + settings: CouchDBConnection; +} | { + type: "s3"; + settings: BucketSyncSetting; +} | { + type: "p2p"; + settings: P2PConnectionInfo; +} | { + type: "webdav"; + settings: any; +}; +export declare class ConnectionStringParser { + /** + * Restore settings from URI + */ + static parse(uriString: string): RemoteConfigurationResult; + /** + * 設定からURIを生成する + */ + static serialize(config: RemoteConfigurationResult): string; + private static parseCouchDB; + private static serializeCouchDB; + private static parseS3; + private static serializeS3; + private static parseP2P; + private static serializeP2P; +} diff --git a/_types/lib/src/common/LSError.d.ts b/_types/lib/src/common/LSError.d.ts new file mode 100644 index 0000000..101cc04 --- /dev/null +++ b/_types/lib/src/common/LSError.d.ts @@ -0,0 +1,47 @@ +interface ErrorWithCause extends Error { + cause?: unknown; +} +/** + * Error class for Self-hosted LiveSync errors. + * This class extends the base LiveSyncError class and provides additional context for errors related to LiveSync operations. + * It includes a name property and a cause property to capture the original error. + * The status property returns the HTTP status code if available, defaulting to 500 for internal server errors. + * The class also includes static methods to check whether an error is caused by a specific error class. + */ +export declare class LiveSyncError extends Error implements ErrorWithCause { + name: string; + cause?: Error | object | string; + overrideStatus?: number; + /** + * Returns the HTTP status code associated with the error, if available. + * If the error has a status property, it returns that; otherwise, it defaults to 500 (Internal Server Error). + * @returns {number} The HTTP status code. + */ + get status(): number; + /** + * Constructs a new LiveSyncError instance. + * @param message The error message to be displayed. + */ + constructor(message: string, options?: { + cause?: unknown; + status?: number; + }); + /** + * Determines whether an error is caused by a specific error class. + * @param error The error to examine. + * @param errorClass The error class to compare against. + * @returns True if the error is caused by the specified error class; otherwise, false. + * @example + * LiveSyncError.isCausedBy(someSyncParamsFetchError, SyncParamsNotFoundError); // Returns true if the error is caused by SyncParamsNotFoundError; this is usually represented as SyncParamsFetchError at the uppermost layer. + */ + static isCausedBy(error: unknown, errorClass: new (...args: any[]) => T): boolean; + /** + * Creates a new instance of the error class from an existing error. + * @param error The error to wrap. + * @returns A new instance of the error class with the original error's message and stack trace. + */ + static fromError(this: T, error: unknown): InstanceType; +} +export declare class LiveSyncFatalError extends LiveSyncError { +} +export {}; diff --git a/_types/lib/src/common/configForDoc.d.ts b/_types/lib/src/common/configForDoc.d.ts new file mode 100644 index 0000000..5f6f5da --- /dev/null +++ b/_types/lib/src/common/configForDoc.d.ts @@ -0,0 +1,78 @@ +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +declare enum ConditionType { + PLATFORM_CASE_INSENSITIVE = "platform-case-insensitive", + PLATFORM_CASE_SENSITIVE = "platform-case-sensitive", + REMOTE_CASE_SENSITIVE = "remote-case-sensitive" +} +export declare enum RuleLevel { + Must = 0, + Necessary = 1, + Recommended = 2, + Optional = 3 +} +type BaseRule = { + level?: RuleLevel; + requireRebuild?: boolean; + requireRebuildLocal?: boolean; + recommendRebuild?: boolean; + reason?: string; + reasonFunc?: (settings: Partial) => string; + condition?: ConditionType[]; + detectionFunc?: (settings: Partial) => boolean; + value?: TValue; + valueDisplay?: string; + valueDisplayFunc?: (settings: Partial) => string; + obsoleteValues?: TValue[]; +}; +type NumberRuleExact = BaseRule<"number", number> & {}; +type NumberRuleRange = BaseRule<"number", number> & { + min?: number; + max?: number; + step?: number; +}; +type StringRangeRule = BaseRule<"string", string> & { + minLength?: number; + maxLength?: number; + regexp?: string; +}; +type StringRule = BaseRule<"string", string> & {}; +type BooleanRule = BaseRule<"boolean", boolean> & {}; +export type RuleForType = T extends number ? NumberRuleExact | NumberRuleRange : T extends string ? StringRule | StringRangeRule : T extends boolean ? BooleanRule : never; +export type AnyRule = NumberRuleExact | NumberRuleRange | StringRule | StringRangeRule | BooleanRule; +type DoctorCheckSettings = Omit, "remoteConfigurations" | "pluginSyncExtendedSetting">; +export type DoctorRegulation = { + version: string; + rules: { + [P in keyof DoctorCheckSettings]: RuleForType; + }; +}; +export declare const DoctorRegulationV0_24_16: DoctorRegulation; +export declare const DoctorRegulationV0_24_30: DoctorRegulation; +export declare const DoctorRegulationV0_25_0: DoctorRegulation; +export declare const DoctorRegulationV0_25_27: DoctorRegulation; +export declare const DoctorRegulation: DoctorRegulation; +export declare function checkUnsuitableValues(setting: Partial, regulation?: DoctorRegulation): DoctorRegulation; +export declare const RebuildOptions: { + readonly AutomaticAcceptable: 0; + readonly ConfirmIfRequired: 1; + readonly SkipEvenIfRequired: 2; +}; +export type RebuildOptionsType = (typeof RebuildOptions)[keyof typeof RebuildOptions]; +export type DoctorOptions = { + localRebuild: RebuildOptionsType; + remoteRebuild: RebuildOptionsType; + activateReason?: string; + forceRescan?: boolean; +}; +export type DoctorResult = { + settings: ObsidianLiveSyncSettings; + shouldRebuild: boolean; + shouldRebuildLocal: boolean; + isModified: boolean; +}; +export type HasConfirm = { + confirm: Confirm; +}; +export declare function performDoctorConsultation(env: HasConfirm, settings: ObsidianLiveSyncSettings, { localRebuild, remoteRebuild, activateReason, forceRescan, }: DoctorOptions): Promise; +export {}; diff --git a/_types/lib/src/common/context.d.ts b/_types/lib/src/common/context.d.ts new file mode 100644 index 0000000..1f08de6 --- /dev/null +++ b/_types/lib/src/common/context.d.ts @@ -0,0 +1,16 @@ +declare class Context = object> { + _data: Partial; + children: WeakRef>[]; + parent?: Context; + constructor(base?: Context, data?: Partial); + set(key: V, value: T[V]): void; + get(key: V): T[V] | undefined; + setInGlobalContext(key: V, value: T[V]): void; + setInNearestContext(key: V, value: T[V]): void; + spawnContext>(data?: V): Context; + _disposeChild(child: Context): void; + dispose(): void; +} +export declare function getContext = object>(data?: T): Context; +export declare function getIndependentContext = object>(data?: T): Context; +export {}; diff --git a/_types/lib/src/common/coreEnvFunctions.d.ts b/_types/lib/src/common/coreEnvFunctions.d.ts new file mode 100644 index 0000000..f809b82 --- /dev/null +++ b/_types/lib/src/common/coreEnvFunctions.d.ts @@ -0,0 +1,21 @@ +import type { getLanguage as ObsidianGetLanguage } from "obsidian"; +export declare function setGetLanguage(func: typeof ObsidianGetLanguage): void; +export declare function getLanguage(): string; +export declare const compatGlobal: typeof window; +export type CompatTimeoutHandle = ReturnType | number; +export type CompatIntervalHandle = ReturnType | number; +/** + * A wrapper around the global fetch function to ensure compatibility across different environments. + * In Obsidian, they recommend using their own requestUrl for better performance and reliability. + * However, at least for now, requestUrl cannot handle multiple concurrent requests, which causes + * problems for synchronise lively. So we will use the global fetch for now. + * If the situation changes in the future, change this function to use requestUrl. + * @param {RequestInfo} input The resource that you wish to fetch. Can be either a string or a Request object. + * @param {RequestInit} [init] An options object containing any custom settings that you want to apply to the request. + * @returns {Promise} A Promise that resolves to the Response to that request, whether it is successful or not. + */ +export declare const _fetch: { + (input: RequestInfo | URL, init?: RequestInit): Promise; + (input: RequestInfo | URL, init?: RequestInit): Promise; +} & typeof fetch; +export declare const _activeDocument: Document; diff --git a/_types/lib/src/common/coreEnvVars.d.ts b/_types/lib/src/common/coreEnvVars.d.ts new file mode 100644 index 0000000..05d180d --- /dev/null +++ b/_types/lib/src/common/coreEnvVars.d.ts @@ -0,0 +1,3 @@ +declare const manifestVersion: string; +declare const packageVersion: string; +export { manifestVersion, packageVersion }; diff --git a/_types/lib/src/common/i18n.d.ts b/_types/lib/src/common/i18n.d.ts new file mode 100644 index 0000000..0e4563f --- /dev/null +++ b/_types/lib/src/common/i18n.d.ts @@ -0,0 +1,18 @@ +import type { AllMessageKeys, I18N_LANGS } from "./rosetta"; +import type { TaggedType } from "@lib/common/models/shared.type.util"; +export declare let currentLang: I18N_LANGS; +export declare function getResolvedLang(lang?: I18N_LANGS): I18N_LANGS; +export declare function isAutoDisplayLanguage(lang: I18N_LANGS): boolean; +export declare function __getMissingTranslations(): string[]; +export declare function __onMissingTranslation(callback: (key: string) => void): void; +export declare function setLang(lang: I18N_LANGS): void; +export declare function $t(message: string, lang?: I18N_LANGS): string; +export declare function translateIfAvailable(message: string, lang?: I18N_LANGS): string; +/** + * TagFunction to Automatically translate. + * @param strings + * @param values + * @returns + */ +export declare function $f(strings: TemplateStringsArray, ...values: string[]): string; +export declare function $msg(key: T, params?: Record, lang?: I18N_LANGS): TaggedType; diff --git a/_types/lib/src/common/logger.d.ts b/_types/lib/src/common/logger.d.ts new file mode 100644 index 0000000..94a5178 --- /dev/null +++ b/_types/lib/src/common/logger.d.ts @@ -0,0 +1,2 @@ +export * from "octagonal-wheels/common/logger"; +export type * from "octagonal-wheels/common/logger"; diff --git a/_types/lib/src/common/messages/combinedMessages.dev.d.ts b/_types/lib/src/common/messages/combinedMessages.dev.d.ts new file mode 100644 index 0000000..5f71efa --- /dev/null +++ b/_types/lib/src/common/messages/combinedMessages.dev.d.ts @@ -0,0 +1,7 @@ +import { PartialMessages as def } from "./def.ts"; +import { type MESSAGE } from "@lib/common/rosetta.ts"; +type MessageKeys = keyof typeof def.def; +export declare const allMessages: { + [key: string]: MESSAGE; +}; +export { type MessageKeys }; diff --git a/_types/lib/src/common/messages/combinedMessages.prod.d.ts b/_types/lib/src/common/messages/combinedMessages.prod.d.ts new file mode 100644 index 0000000..91a41d6 --- /dev/null +++ b/_types/lib/src/common/messages/combinedMessages.prod.d.ts @@ -0,0 +1,9264 @@ +export declare const allMessages: { + readonly "(Active)": { + readonly def: "(Active)"; + readonly es: "(Activo)"; + readonly ja: "(有効)"; + readonly ko: "(활성)"; + readonly ru: "(Активна)"; + readonly zh: "(已启用)"; + readonly "zh-tw": "(已啟用)"; + }; + readonly "(BETA) Always overwrite with a newer file": { + readonly def: "(BETA) Always overwrite with a newer file"; + readonly es: "(BETA) Sobrescribir siempre con archivo más nuevo"; + readonly fr: "(BÊTA) Toujours écraser avec un fichier plus récent"; + readonly he: "(BETA) תמיד לדרוס עם קובץ חדש יותר"; + readonly ja: "(ベータ機能) 常に新しいファイルで上書きする"; + readonly ko: "(베타) 항상 새로운 파일로 덮어쓰기"; + readonly ru: "(БЕТА) Всегда перезаписывать более новым файлом"; + readonly zh: "始终使用更新的文件覆盖(测试版)"; + }; + readonly "(Beta) Use ignore files": { + readonly def: "(Beta) Use ignore files"; + readonly es: "(Beta) Usar archivos de ignorar"; + readonly fr: "(Bêta) Utiliser les fichiers d'exclusion"; + readonly he: "(בטא) שימוש בקבצי התעלמות"; + readonly ja: "(ベータ機能) 除外ファイル(ignore)の使用"; + readonly ko: "(베타) 제외 규칙 파일 사용"; + readonly ru: "(Бета) Использовать файлы игнорирования"; + readonly zh: "(测试版)使用忽略文件"; + }; + readonly "(Days passed, 0 to disable automatic-deletion)": { + readonly def: "(Days passed, 0 to disable automatic-deletion)"; + readonly es: "(Días transcurridos, 0 para desactivar)"; + readonly fr: "(Jours écoulés, 0 pour désactiver la suppression automatique)"; + readonly he: "(ימים שעברו; 0 לביטול מחיקה אוטומטית)"; + readonly ja: "(経過日数、0で自動削除を無効化)"; + readonly ko: "(지난 일수, 0으로 설정하면 자동 삭제 비활성화)"; + readonly ru: "(Дней прошло, 0 для отключения автоматического удаления)"; + readonly zh: "(已过天数,0为禁用自动删除)"; + }; + readonly "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": { + readonly def: "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended."; + readonly es: "(Ej: Leer chunks online) Lee chunks directamente en línea. Aumente tamaño de chunks personalizados"; + readonly fr: "(ex. Lire les fragments en ligne) Si cette option est activée, LiveSync lit les fragments directement en ligne au lieu de les répliquer localement. L'augmentation de la taille personnalisée des fragments est recommandée."; + readonly he: "(לדוגמה: קריאת נתחים אונליין) אם אפשרות זו מופעלת, LiveSync קורא נתחים ישירות מהשרת מבלי לשכפל אותם מקומית. מומלץ להגדיל את גודל הנתח המותאם אישית."; + readonly ja: "(例: チャンクをオンラインで読む) このオプションを有効にすると、LiveSyncはチャンクをローカルに複製せず、直接オンラインで読み込みます。カスタムチャンクサイズを増やすことをお勧めします。"; + readonly ko: "(예: 청크를 원격에서 읽음) 이 옵션을 활성화하면, LiveSync는 청크를 로컬에 복제하지 않고 원격에서 직접 읽습니다. 커스텀 청크 크기를 키우는 것을 권장합니다."; + readonly ru: "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended."; + readonly zh: "(例如,在线读取块)如果启用此选项,LiveSync 将直接在线读取块,而不是在本地复制块。建议增加自定义块大小"; + }; + readonly "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": { + readonly def: "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used."; + readonly es: "(MB) Saltar cambios en archivos locales/remotos mayores a este tamaño. Si se reduce, se usará versión nueva"; + readonly fr: "(Mo) Si cette valeur est définie, les modifications des fichiers locaux et distants plus grands que cette taille seront ignorées. Si le fichier redevient plus petit, une version plus récente sera utilisée."; + readonly he: "(MB) אם ערך זה מוגדר, שינויים בקבצים מקומיים ומרוחקים הגדולים מגודל זה יידלגו. אם הקובץ יקטן שוב, ייעשה שימוש בגרסה החדשה יותר."; + readonly ja: "(MB) この値を設定すると、これより大きいサイズのローカルファイルやリモートファイルの変更はスキップされます。ファイルが再び小さくなった場合は、新しいものが使用されます。"; + readonly ko: "(MB) 이 값이 설정되면, 이보다 큰 로컬 및 원격 파일의 변경 사항은 건너뜁니다. 파일이 다시 작아지면 더 새로운 파일이 사용됩니다."; + readonly ru: "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used."; + readonly zh: "(MB)如果设置了此项,大于此大小的本地和远程文件的更改将被跳过。如果文件再次变小,将使用更新的文件"; + }; + readonly "(Mega chars)": { + readonly def: "(Mega chars)"; + readonly es: "(Millones de caracteres)"; + readonly fr: "(Méga caractères)"; + readonly he: "(מגה תווים)"; + readonly ja: "(メガ文字)"; + readonly ko: "(메가 문자)"; + readonly ru: "(Мега символов)"; + readonly zh: "(百万字符)"; + }; + readonly "(Not recommended) If set, credentials will be stored in the file.": { + readonly def: "(Not recommended) If set, credentials will be stored in the file."; + readonly es: "(No recomendado) Almacena credenciales en el archivo"; + readonly fr: "(Non recommandé) Si activé, les identifiants seront stockés dans le fichier."; + readonly he: "(לא מומלץ) אם מוגדר, פרטי הגישה יישמרו בקובץ."; + readonly ja: "(非推奨) 設定した場合、認証情報がファイルに保存されます。"; + readonly ko: "(권장하지 않음) 설정한 경우 자격 증명이 파일에 저장됩니다."; + readonly ru: "(Not recommended) If set, credentials will be stored in the file."; + readonly zh: "(不建议)如果设置,凭据将存储在文件中"; + }; + readonly "(Obsolete) Use an old adapter for compatibility": { + readonly def: "(Obsolete) Use an old adapter for compatibility"; + readonly es: "(Obsoleto) Usar adaptador antiguo"; + readonly fr: "(Obsolète) Utiliser un ancien adaptateur pour la compatibilité"; + readonly he: "(מיושן) שימוש במתאם ישן לתאימות לאחור"; + readonly ja: "(廃止済み)古いアダプターを互換性のために利用"; + readonly ko: "(사용 중단) 호환성을 위해 이전 어댑터 사용"; + readonly ru: "(Устарело) Использовать старый адаптер для совместимости"; + readonly zh: "(已弃用)为兼容性使用旧适配器"; + }; + readonly "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": { + readonly def: "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files."; + readonly es: "(RegExp) Déjelo vacío para sincronizar todos los archivos. Defina un filtro como expresión regular para limitar los archivos que se sincronizan."; + readonly ja: "(正規表現)空欄で全ファイルを同期します。正規表現を指定すると、同期対象のファイルを絞り込めます。"; + readonly ko: "(정규식) 비워 두면 모든 파일을 동기화합니다. 정규식을 지정하면 동기화할 파일을 제한할 수 있습니다."; + readonly ru: "(RegExp) Оставьте пустым, чтобы синхронизировать все файлы. Укажите регулярное выражение, чтобы ограничить синхронизируемые файлы."; + readonly zh: "(正则表达式)留空表示同步所有文件。可设置正则表达式来限制需要同步的文件。"; + readonly "zh-tw": "(正則表示式)留空即同步所有檔案。設定正則表示式可限制要同步的檔案。"; + }; + readonly "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": { + readonly def: "(RegExp) If this is set, any changes to local and remote files that match this will be skipped."; + readonly es: "(RegExp) Si se establece, se omitirá cualquier cambio en archivos locales y remotos que coincida con este patrón."; + readonly ja: "(正規表現)設定すると、これに一致するローカル/リモートファイルの変更はすべてスキップされます。"; + readonly ko: "(정규식) 설정하면 이 패턴과 일치하는 로컬 및 원격 파일 변경은 모두 건너뜁니다."; + readonly ru: "(RegExp) Если задано, любые изменения локальных и удалённых файлов, соответствующих этому шаблону, будут пропускаться."; + readonly zh: "(正则表达式)如果已设置,则所有匹配此模式的本地和远端文件变更都会被跳过。"; + readonly "zh-tw": "(正則表示式)若已設定,所有符合此模式的本機與遠端檔案變更都會被略過。"; + }; + readonly "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": { + readonly def: "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch."; + readonly es: "(Seleccione esto si ya utiliza la sincronización en otro ordenador o teléfono). Esta opción es adecuada si desea añadir este dispositivo a una configuración de LiveSync existente。"; + readonly ja: "(別の PC やスマートフォンですでに同期を利用している場合に選択してください。)この端末を既存の LiveSync 構成に追加する場合に適しています。"; + readonly ko: "(다른 컴퓨터나 스마트폰에서 이미 동기화를 사용 중인 경우 선택하세요.) 이 장치를 기존 LiveSync 구성에 추가하려는 경우에 적합합니다。"; + readonly ru: "(Выберите этот вариант, если вы уже используете синхронизацию на другом компьютере или смартфоне.) Он подходит, если вы хотите добавить это устройство к уже существующей конфигурации LiveSync。"; + readonly zh: "(如果你已经在另一台电脑或手机上使用同步,请选择此项。)此选项适合将当前设备加入现有 LiveSync 配置的用户。"; + readonly "zh-tw": "(如果你已經在另一台電腦或手機上使用同步,請選擇此項。)此選項適合將目前裝置加入既有 LiveSync 設定的使用者。"; + }; + readonly "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": { + readonly def: "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch."; + readonly es: "(Seleccione esto si está configurando este dispositivo como el primer dispositivo de sincronización). Esta opción es adecuada si es nuevo en LiveSync y desea configurarlo desde cero。"; + readonly ja: "(この端末を最初の同期端末として設定する場合に選択してください。)LiveSync を初めて利用し、最初から設定したい場合に適しています。"; + readonly ko: "(이 장치를 첫 번째 동기화 장치로 설정하는 경우 선택하세요.) LiveSync를 처음 사용하며 처음부터 설정하려는 경우에 적합합니다。"; + readonly ru: "(Выберите этот вариант, если настраиваете это устройство как первое устройство синхронизации.) Он подходит, если вы впервые используете LiveSync и хотите настроить всё с нуля。"; + readonly zh: "(如果你正在将此设备配置为第一台同步设备,请选择此项。)此选项适合初次使用 LiveSync,并希望从头开始配置的用户。"; + readonly "zh-tw": "(如果你正在將此裝置設定為第一台同步裝置,請選擇此項。)此選項適合初次使用 LiveSync,並希望從頭開始設定的使用者。"; + }; + readonly "> [!INFO]- The connected devices have been detected as follows:\n${devices}": { + readonly def: "> [!INFO]- The connected devices have been detected as follows:\n${devices}"; + readonly ja: "> [!INFO]- 次の接続済みデバイスが検出されました:\n${devices}"; + readonly ko: "> [!INFO]- 다음 연결된 기기가 감지되었습니다:\n${devices}"; + readonly ru: "> [!INFO]- Обнаружены следующие подключённые устройства:\n${devices}"; + readonly zh: "> [!INFO]- 已检测到以下已连接设备:\n${devices}"; + readonly "zh-tw": "> [!INFO]- 已偵測到以下已連線裝置:\n${devices}"; + }; + readonly "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": { + readonly def: "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration."; + readonly es: "Un URI de configuración es una única cadena de texto que contiene la dirección del servidor y los datos de autenticación. Si el script de instalación de su servidor generó un URI, usarlo proporciona una configuración sencilla y segura。"; + readonly ja: "Setup URI は、サーバーアドレスと認証情報を含む 1 本の文字列です。サーバーのインストールスクリプトで生成された URI がある場合は、それを使うと簡単かつ安全に設定できます。"; + readonly ko: "설정 URI는 서버 주소와 인증 정보를 포함한 단일 문자열입니다. 서버 설치 스크립트가 URI를 생성했다면 이를 사용하면 간단하고 안전하게 구성할 수 있습니다。"; + readonly ru: "Setup URI — это одна строка текста, содержащая адрес сервера и данные аутентификации. Если URI был создан скриптом установки сервера, его использование обеспечивает простую и безопасную настройку。"; + readonly zh: "Setup URI 是一段包含服务器地址与认证信息的文本。如果服务器安装脚本已经生成了 URI,使用它可以更简单且更安全地完成配置。"; + readonly "zh-tw": "Setup URI 是一段包含伺服器位址與驗證資訊的文字。如果伺服器安裝腳本已經產生 URI,使用它可以更簡單且更安全地完成設定。"; + }; + readonly "Access Key": { + readonly def: "Access Key"; + readonly es: "Clave de acceso"; + readonly fr: "Clé d'accès"; + readonly he: "מפתח גישה"; + readonly ja: "アクセスキー"; + readonly ko: "액세스 키"; + readonly ru: "Ключ доступа"; + readonly zh: "访问密钥"; + }; + readonly Activate: { + readonly def: "Activate"; + readonly es: "Activar"; + readonly ja: "有効化"; + readonly ko: "활성화"; + readonly ru: "Активировать"; + readonly zh: "启用"; + readonly "zh-tw": "啟用"; + }; + readonly "Active Remote Configuration": { + readonly def: "Active Remote Configuration"; + readonly fr: "Configuration distante active"; + readonly he: "תצורת שרת מרוחק פעיל"; + readonly ru: "Активная удалённая конфигурация"; + readonly zh: "生效中的远程配置"; + readonly "zh-tw": "目前啟用的遠端設定"; + }; + readonly "Add default patterns": { + readonly def: "Add default patterns"; + readonly es: "Añadir patrones predeterminados"; + readonly ja: "デフォルトパターンを追加"; + readonly ko: "기본 패턴 추가"; + readonly ru: "Добавить шаблоны по умолчанию"; + readonly zh: "添加默认模式"; + readonly "zh-tw": "新增預設模式"; + }; + readonly "Add new connection": { + readonly def: "Add new connection"; + readonly es: "Añadir conexión"; + readonly ja: "接続を追加"; + readonly ko: "연결 추가"; + readonly ru: "Добавить подключение"; + readonly zh: "新增连接"; + readonly "zh-tw": "新增連線"; + }; + readonly "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": { + readonly def: "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection."; + readonly ja: "すべてのデバイスで進捗値が同じです(${progress})。デバイスは同期されているようなので、Garbage Collection を続行できます。"; + readonly ko: "모든 기기의 진행 값이 동일합니다(${progress}). 기기들이 동기화된 것으로 보이므로 Garbage Collection을 진행할 수 있습니다."; + readonly ru: "У всех устройств одинаковое значение прогресса (${progress}). Похоже, ваши устройства синхронизированы, и можно продолжать Garbage Collection."; + readonly zh: "所有设备的进度值均相同(${progress})。看起来你的设备已经同步,可以继续执行垃圾回收。"; + readonly "zh-tw": "所有裝置的進度值均相同(${progress})。看起來你的裝置已同步,可以繼續執行垃圾回收。"; + }; + readonly "Always prompt merge conflicts": { + readonly def: "Always prompt merge conflicts"; + readonly es: "Siempre preguntar en conflictos"; + readonly fr: "Toujours demander pour les conflits de fusion"; + readonly he: "תמיד להציג בקשת אישור לקונפליקטי מיזוג"; + readonly ja: "常に競合は手動で解決する"; + readonly ko: "항상 병합 충돌 알림"; + readonly ru: "Всегда запрашивать разрешение конфликтов слияния"; + readonly zh: "始终提示合并冲突"; + readonly "zh-tw": "總是提示合併衝突"; + }; + readonly Analyse: { + readonly def: "Analyse"; + readonly fr: "Analyser"; + readonly he: "ניתוח"; + readonly ru: "Анализировать"; + readonly zh: "立即分析"; + readonly "zh-tw": "分析"; + }; + readonly "Analyse database usage": { + readonly def: "Analyse database usage"; + readonly fr: "Analyser l'utilisation de la base de données"; + readonly he: "ניתוח שימוש במסד נתונים"; + readonly ja: "データベース使用状況を分析"; + readonly ko: "데이터베이스 사용량 분석"; + readonly ru: "Анализ использования базы данных"; + readonly zh: "分析数据库使用情况"; + readonly "zh-tw": "分析資料庫使用情況"; + }; + readonly "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": { + readonly def: "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like."; + readonly fr: "Analyser l'utilisation de la base de données et générer un rapport TSV pour un diagnostic personnel. Vous pouvez coller le rapport généré dans le tableur de votre choix."; + readonly he: "נתח שימוש במסד הנתונים וצור דו\"ח TSV לאבחון עצמי. ניתן להדביק את הדו\"ח שנוצר בכל גיליון אלקטרוני."; + readonly ja: "データベース使用状況を分析し、自分で診断できるよう TSV レポートを生成します。生成したレポートは任意のスプレッドシートに貼り付けて確認できます。"; + readonly ko: "데이터베이스 사용량을 분석하고 직접 진단할 수 있도록 TSV 보고서를 생성합니다. 생성된 보고서는 원하는 스프레드시트에 붙여 넣어 확인할 수 있습니다."; + readonly ru: "Проанализируйте использование базы данных и создайте TSV-отчёт для самостоятельной диагностики. Полученный отчёт можно вставить в любую удобную для вас таблицу."; + readonly zh: "分析数据库使用情况并生成 TSV 报告以供您自行诊断。您可以将生成的报告粘贴到您喜欢的任何电子表格中。"; + readonly "zh-tw": "分析資料庫使用情況並產生 TSV 報告,方便你自行診斷。你可以將產生的報告貼到任何慣用的試算表中查看。"; + }; + readonly "Apply Latest Change if Conflicting": { + readonly def: "Apply Latest Change if Conflicting"; + readonly es: "Aplicar último cambio en conflictos"; + readonly fr: "Appliquer la dernière modification en cas de conflit"; + readonly he: "החל שינוי אחרון בעת קונפליקט"; + readonly ja: "競合がある場合は最新の変更を適用する"; + readonly ko: "충돌 시 최신 변경 사항 적용"; + readonly ru: "Применить последнее изменение при конфликте"; + readonly zh: "如果冲突则应用最新更改"; + readonly "zh-tw": "發生衝突時套用最新變更"; + }; + readonly "Apply preset configuration": { + readonly def: "Apply preset configuration"; + readonly es: "Aplicar configuración predefinida"; + readonly fr: "Appliquer une configuration prédéfinie"; + readonly he: "החל תצורה קבועה מראש"; + readonly ja: "プリセットを適用する"; + readonly ko: "프리셋 구성 적용"; + readonly ru: "Применить предустановленную конфигурацию"; + readonly zh: "应用预设配置"; + readonly "zh-tw": "套用預設配置"; + }; + readonly "Ask a passphrase at every launch": { + readonly def: "Ask a passphrase at every launch"; + readonly es: "Solicitar la frase de contraseña en cada inicio"; + readonly ja: "起動のたびにパスフレーズを確認"; + readonly ko: "시작할 때마다 암호문구 묻기"; + readonly ru: "Запрашивать парольную фразу при каждом запуске"; + readonly zh: "每次启动时询问密码短语"; + readonly "zh-tw": "每次啟動時都詢問密語"; + }; + readonly "Automatically Sync all files when opening Obsidian.": { + readonly def: "Automatically Sync all files when opening Obsidian."; + readonly es: "Sincronizar automáticamente todos los archivos al abrir Obsidian"; + readonly fr: "Synchroniser automatiquement tous les fichiers à l'ouverture d'Obsidian."; + readonly he: "סנכרן את כל הקבצים אוטומטית עם פתיחת Obsidian."; + readonly ja: "Obsidian起動時にすべてのファイルを自動同期します。"; + readonly ko: "Obsidian을 열 때 모든 파일을 자동으로 동기화합니다."; + readonly ru: "Автоматически синхронизировать все файлы при открытии Obsidian."; + readonly zh: "打开 Obsidian 时自动同步所有文件"; + readonly "zh-tw": "開啟 Obsidian 時自動同步所有檔案。"; + }; + readonly Back: { + readonly def: "Back"; + readonly es: "Volver"; + readonly ja: "戻る"; + readonly ko: "뒤로"; + readonly ru: "Назад"; + readonly zh: "返回"; + readonly "zh-tw": "返回"; + }; + readonly "Back to non-configured": { + readonly def: "Back to non-configured"; + readonly es: "Volver a no configurado"; + readonly ja: "未設定状態に戻す"; + readonly ko: "미구성 상태로 되돌리기"; + readonly ru: "Вернуть в состояние без настройки"; + readonly zh: "恢复为未配置状态"; + readonly "zh-tw": "恢復為未設定狀態"; + }; + readonly "Batch database update": { + readonly def: "Batch database update"; + readonly es: "Actualización por lotes de BD"; + readonly fr: "Mise à jour groupée de la base de données"; + readonly he: "עדכון אצווה למסד נתונים"; + readonly ja: "データベースのバッチ更新"; + readonly ko: "일괄 데이터베이스 업데이트"; + readonly ru: "Пакетное обновление базы данных"; + readonly zh: "批量数据库更新"; + readonly "zh-tw": "批次更新資料庫"; + }; + readonly "Batch limit": { + readonly def: "Batch limit"; + readonly es: "Límite de lotes"; + readonly fr: "Limite de lot"; + readonly he: "מגבלת אצווה"; + readonly ja: "バッチの上限"; + readonly ko: "일괄 제한"; + readonly ru: "Пакетный лимит"; + readonly zh: "批量限制"; + readonly "zh-tw": "批次上限"; + }; + readonly "Batch size": { + readonly def: "Batch size"; + readonly es: "Tamaño de lote"; + readonly fr: "Taille de lot"; + readonly he: "גודל אצווה"; + readonly ja: "バッチ容量"; + readonly ko: "일괄 크기"; + readonly ru: "Размер пакета"; + readonly zh: "批量大小"; + readonly "zh-tw": "批次大小"; + }; + readonly "Batch size of on-demand fetching": { + readonly def: "Batch size of on-demand fetching"; + readonly es: "Tamaño de lote para obtención bajo demanda"; + readonly fr: "Taille de lot pour la récupération à la demande"; + readonly he: "גודל אצווה במשיכה לפי דרישה"; + readonly ja: "オンデマンド取得のバッチサイズ"; + readonly ko: "필요 시 가져올 청크 묶음 크기"; + readonly ru: "Размер пакета при запросе по требованию"; + readonly zh: "按需获取的批量大小"; + readonly "zh-tw": "按需抓取的批次大小"; + }; + readonly "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": { + readonly def: "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this."; + readonly es: "Antes de v0.17.16 usábamos adaptador antiguo. Nuevo adaptador requiere reconstruir BD local. Desactive cuando pueda"; + readonly fr: "Avant la version v0.17.16, nous utilisions un ancien adaptateur pour la base de données locale. Le nouvel adaptateur est désormais recommandé. Cependant, il nécessite une reconstruction de la base locale. Veuillez désactiver cette option lorsque vous aurez suffisamment de temps. Si elle reste activée, il vous sera également demandé de la désactiver lors de la récupération depuis la base distante."; + readonly he: "לפני גרסה 0.17.16, השתמשנו במתאם ישן למסד הנתונים המקומי. כעת המתאם החדש מועדף. עם זאת, הדבר מצריך בנייה מחדש של מסד הנתונים המקומי. אנא כבה אפשרות זו כשיש לך זמן פנוי. אם תשאיר אותה מופעלת, גם בעת משיכה ממסד הנתונים המרוחק, תתבקש לכבות אותה."; + readonly ja: "v0.17.6までは古いアダプターをローカル用のデータベースに使用していましたが、現在は新しいアダプターを推奨しています。しかし、新しいアダプターに変更するにはローカルデータベースの再構築が必要です。有効のままにしておくと、リモートデータベースからフェッチする場合に、この設定を無効にするかの質問が表示されます。"; + readonly ko: "v0.17.16 이전에는 로컬 데이터베이스에 이전 어댑터를 사용했습니다. 이제는 새로운 어댑터를 권장합니다. 하지만 로컬 데이터베이스 재구축이 필요합니다. 충분한 시간이 있을 때 이 토글을 비활성화해 주세요. 활성화된 상태로 두면 원격 데이터베이스에서 가져올 때도 이를 비활성화하라는 메시지가 나타납니다."; + readonly ru: "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this."; + readonly zh: "在 v0.17.16 之前,我们使用旧适配器作为本地数据库。现在首选新适配器。但是,它需要重建本地数据库。请在有足够时间时禁用此开关。如果保持启用状态,并且在从远程数据库获取时,系统将要求您禁用此开关。"; + }; + readonly "Bucket Name": { + readonly def: "Bucket Name"; + readonly es: "Nombre del bucket"; + readonly fr: "Nom du bucket"; + readonly he: "שם דלי (Bucket)"; + readonly ja: "バケット名"; + readonly ko: "버킷 이름"; + readonly ru: "Имя бакета"; + readonly zh: "存储桶名称"; + readonly "zh-tw": "儲存桶名稱"; + }; + readonly Cancel: { + readonly def: "Cancel"; + readonly es: "Cancelar"; + readonly ja: "キャンセル"; + readonly ko: "취소"; + readonly ru: "Отмена"; + readonly zh: "取消"; + readonly "zh-tw": "取消"; + }; + readonly "Cancel Garbage Collection": { + readonly def: "Cancel Garbage Collection"; + readonly ja: "Garbage Collection をキャンセル"; + readonly ko: "Garbage Collection 취소"; + readonly ru: "Отменить Garbage Collection"; + readonly zh: "取消垃圾回收"; + readonly "zh-tw": "取消垃圾回收"; + }; + readonly "Changing this setting requires migrating existing data (a bit time may be taken) and restarting Obsidian. Please make sure to back up your data before proceeding.": { + readonly def: "Changing this setting requires migrating existing data (a bit time may be taken) and restarting Obsidian. Please make sure to back up your data before proceeding."; + }; + readonly Check: { + readonly def: "Check"; + readonly fr: "Vérifier"; + readonly he: "בדוק"; + readonly ru: "Проверить"; + readonly zh: "立即检查"; + readonly "zh-tw": "檢查"; + }; + readonly "Check and convert non-path-obfuscated files": { + readonly def: "Check and convert non-path-obfuscated files"; + readonly es: "Comprobar y convertir archivos sin ofuscación de ruta"; + readonly ja: "パス難読化されていないファイルを確認して変換"; + readonly ko: "경로 난독화되지 않은 파일 검사 및 변환"; + readonly ru: "Проверить и преобразовать файлы без обфускации пути"; + readonly zh: "检查并转换未进行路径混淆的文件"; + readonly "zh-tw": "檢查並轉換未進行路徑混淆的檔案"; + }; + readonly "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": { + readonly def: "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary."; + readonly es: "Comprueba los documentos que aún no se hayan convertido a identificadores con ruta ofuscada y conviértelos si es necesario."; + readonly ja: "まだパス難読化 ID に変換されていないドキュメントを確認し、必要に応じて変換します。"; + readonly ko: "아직 경로 난독화 ID로 변환되지 않은 문서를 확인하고 필요하면 변환합니다."; + readonly ru: "Проверяет документы, которые ещё не были преобразованы в path-obfuscated ID, и при необходимости преобразует их."; + readonly zh: "检查尚未转换为路径混淆 ID 的文档,并在需要时将其转换。"; + readonly "zh-tw": "檢查尚未轉換為路徑混淆 ID 的文件,並在需要時進行轉換。"; + }; + readonly "cmdConfigSync.showCustomizationSync": { + readonly def: "Show Customization sync"; + readonly es: "Mostrar sincronización de personalización"; + readonly fr: "Afficher la synchronisation de personnalisation"; + readonly he: "הצג סנכרון התאמה אישית"; + readonly ja: "カスタマイズ同期を表示"; + readonly ko: "사용자 설정 동기화 표시"; + readonly ru: "Показать синхронизацию настроек"; + readonly zh: "显示自定义同步"; + readonly "zh-tw": "顯示自訂同步"; + }; + readonly "Comma separated `.gitignore, .dockerignore`": { + readonly def: "Comma separated `.gitignore, .dockerignore`"; + readonly es: "Separados por comas: `.gitignore, .dockerignore`"; + readonly fr: "Séparés par des virgules `.gitignore, .dockerignore`"; + readonly he: "רשימה מופרדת בפסיקים `.gitignore, .dockerignore`"; + readonly ja: "カンマ区切り `.gitignore, .dockerignore`"; + readonly ko: "쉼표로 구분된 `.gitignore, .dockerignore`"; + readonly ru: "Через запятую `.gitignore, .dockerignore`"; + readonly zh: "用逗号分隔,例如 `.gitignore, .dockerignore`"; + }; + readonly "Compaction in progress on remote database...": { + readonly def: "Compaction in progress on remote database..."; + readonly ja: "リモートデータベースでコンパクションを実行中です..."; + readonly ko: "원격 데이터베이스에서 압축을 진행 중입니다..."; + readonly ru: "Выполняется компакция удалённой базы данных..."; + readonly zh: "正在远程数据库上执行压缩..."; + readonly "zh-tw": "正在遠端資料庫上執行壓縮..."; + }; + readonly "Compaction on remote database completed successfully.": { + readonly def: "Compaction on remote database completed successfully."; + readonly ja: "リモートデータベースでのコンパクションが正常に完了しました。"; + readonly ko: "원격 데이터베이스 압축이 성공적으로 완료되었습니다."; + readonly ru: "Компакция удалённой базы данных успешно завершена."; + readonly zh: "远程数据库压缩已成功完成。"; + readonly "zh-tw": "遠端資料庫壓縮已成功完成。"; + }; + readonly "Compaction on remote database failed.": { + readonly def: "Compaction on remote database failed."; + readonly ja: "リモートデータベースでのコンパクションに失敗しました。"; + readonly ko: "원격 데이터베이스 압축에 실패했습니다."; + readonly ru: "Компакция удалённой базы данных завершилась ошибкой."; + readonly zh: "远程数据库压缩失败。"; + readonly "zh-tw": "遠端資料庫壓縮失敗。"; + }; + readonly "Compaction on remote database timed out.": { + readonly def: "Compaction on remote database timed out."; + readonly ja: "リモートデータベースでのコンパクションがタイムアウトしました。"; + readonly ko: "원격 데이터베이스 압축 시간이 초과되었습니다."; + readonly ru: "Время ожидания компакции удалённой базы данных истекло."; + readonly zh: "远程数据库压缩超时。"; + readonly "zh-tw": "遠端資料庫壓縮逾時。"; + }; + readonly "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": { + readonly def: "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep."; + readonly es: "Compara el contenido de los archivos entre la base de datos local y el almacenamiento. Si no coinciden, se te preguntará cuál deseas conservar."; + readonly ja: "ローカルデータベースとストレージ上のファイル内容を比較します。一致しない場合は、どちらを残すか選択できます。"; + readonly ko: "로컬 데이터베이스와 저장소 간의 파일 내용을 비교합니다. 일치하지 않으면 어떤 쪽을 유지할지 묻게 됩니다."; + readonly ru: "Сравнивает содержимое файлов между локальной базой данных и хранилищем. Если они не совпадут, вам предложат выбрать, какую версию сохранить."; + readonly zh: "比较本地数据库与存储中的文件内容;如果不一致,你将被询问要保留哪一份。"; + readonly "zh-tw": "比較本機資料庫與儲存空間中的檔案內容;若不一致,系統會詢問你要保留哪一份。"; + }; + readonly "Compatibility (Conflict Behaviour)": { + readonly def: "Compatibility (Conflict Behaviour)"; + readonly es: "Compatibilidad (comportamiento de conflictos)"; + readonly ja: "互換性(競合時の挙動)"; + readonly ko: "호환성 (충돌 동작)"; + readonly ru: "Совместимость (поведение при конфликтах)"; + readonly zh: "兼容性(冲突行为)"; + readonly "zh-tw": "相容性(衝突行為)"; + }; + readonly "Compatibility (Database structure)": { + readonly def: "Compatibility (Database structure)"; + readonly es: "Compatibilidad (estructura de la base de datos)"; + readonly ja: "互換性(データベース構造)"; + readonly ko: "호환성 (데이터베이스 구조)"; + readonly ru: "Совместимость (структура базы данных)"; + readonly zh: "兼容性(数据库结构)"; + readonly "zh-tw": "相容性(資料庫結構)"; + }; + readonly "Compatibility (Internal API Usage)": { + readonly def: "Compatibility (Internal API Usage)"; + readonly es: "Compatibilidad (uso de la API interna)"; + readonly ja: "互換性(内部 API の利用)"; + readonly ko: "호환성 (내부 API 사용)"; + readonly ru: "Совместимость (использование внутреннего API)"; + readonly zh: "兼容性(内部 API 使用)"; + readonly "zh-tw": "相容性(內部 API 使用)"; + }; + readonly "Compatibility (Metadata)": { + readonly def: "Compatibility (Metadata)"; + readonly es: "Compatibilidad (metadatos)"; + readonly ja: "互換性(メタデータ)"; + readonly ko: "호환성 (메타데이터)"; + readonly ru: "Совместимость (метаданные)"; + readonly zh: "兼容性(元数据)"; + readonly "zh-tw": "相容性(中繼資料)"; + }; + readonly "Compatibility (Remote Database)": { + readonly def: "Compatibility (Remote Database)"; + readonly es: "Compatibilidad (base de datos remota)"; + readonly ja: "互換性(リモートデータベース)"; + readonly ko: "호환성 (원격 데이터베이스)"; + readonly ru: "Совместимость (удалённая база данных)"; + readonly zh: "兼容性(远端数据库)"; + readonly "zh-tw": "相容性(遠端資料庫)"; + }; + readonly "Compatibility (Trouble addressed)": { + readonly def: "Compatibility (Trouble addressed)"; + readonly es: "Compatibilidad (problemas corregidos)"; + readonly ja: "互換性(対処済みの問題)"; + readonly ko: "호환성 (문제 대응)"; + readonly ru: "Совместимость (исправленные проблемы)"; + readonly zh: "兼容性(问题修复)"; + readonly "zh-tw": "相容性(問題修復)"; + }; + readonly "Compute revisions for chunks": { + readonly def: "Compute revisions for chunks"; + readonly fr: "Calculer les révisions pour les fragments"; + readonly he: "חשב גרסאות לנתחים"; + readonly ja: "チャンクの修正(リビジョン)を計算"; + readonly ko: "청크에 대한 리비전 계산"; + readonly ru: "Вычислять ревизии для чанков"; + readonly zh: "为 chunks 计算修订版本(以前的行为)"; + }; + readonly "Configuration Encryption": { + readonly def: "Configuration Encryption"; + readonly es: "Cifrado de configuración"; + readonly ja: "設定の暗号化"; + readonly ko: "구성 암호화"; + readonly ru: "Шифрование конфигурации"; + readonly zh: "配置加密"; + readonly "zh-tw": "設定加密"; + }; + readonly Configure: { + readonly def: "Configure"; + readonly es: "Configurar"; + readonly ja: "設定"; + readonly ko: "설정"; + readonly ru: "Настроить"; + readonly zh: "配置"; + readonly "zh-tw": "設定"; + }; + readonly "Configure And Change Remote": { + readonly def: "Configure And Change Remote"; + readonly es: "Configurar y cambiar remoto"; + readonly ja: "リモートを設定して切り替える"; + readonly ko: "원격 구성 및 변경"; + readonly ru: "Настроить и переключить удалённое хранилище"; + readonly zh: "配置并切换远端"; + readonly "zh-tw": "設定並切換遠端"; + }; + readonly "Configure E2EE": { + readonly def: "Configure E2EE"; + readonly es: "Configurar E2EE"; + readonly ja: "E2EE を設定"; + readonly ko: "E2EE 구성"; + readonly ru: "Настроить сквозное шифрование"; + readonly zh: "配置 E2EE"; + readonly "zh-tw": "設定 E2EE"; + }; + readonly "Configure Remote": { + readonly def: "Configure Remote"; + readonly es: "Configurar remoto"; + readonly ja: "リモートを設定"; + readonly ko: "원격 구성"; + readonly ru: "Настроить удалённое хранилище"; + readonly zh: "配置远端"; + readonly "zh-tw": "設定遠端"; + }; + readonly "Configure the same server information as your other devices again, manually, very advanced users only.": { + readonly def: "Configure the same server information as your other devices again, manually, very advanced users only."; + readonly es: "Configure manualmente la misma información del servidor que en sus otros dispositivos. Solo para usuarios muy avanzados。"; + readonly ja: "他の端末と同じサーバー情報を手動で再入力します。上級者向けの方法です。"; + readonly ko: "다른 장치와 동일한 서버 정보를 다시 수동으로 입력합니다. 고급 사용자 전용입니다。"; + readonly ru: "Снова вручную укажите те же параметры сервера, что и на других устройствах. Только для очень опытных пользователей。"; + readonly zh: "手动重新输入与你其他设备相同的服务器信息。仅适合高级用户。"; + readonly "zh-tw": "手動重新輸入與其他裝置相同的伺服器資訊。僅適合進階使用者。"; + }; + readonly "Connection Method": { + readonly def: "Connection Method"; + readonly es: "Método de conexión"; + readonly ja: "接続方法"; + readonly ko: "연결 방법"; + readonly ru: "Способ подключения"; + readonly zh: "连接方式"; + readonly "zh-tw": "連線方式"; + }; + readonly "Continue to CouchDB setup": { + readonly def: "Continue to CouchDB setup"; + readonly es: "Continuar con la configuración de CouchDB"; + readonly ja: "CouchDB 設定へ進む"; + readonly ko: "CouchDB 설정으로 계속"; + readonly ru: "Перейти к настройке CouchDB"; + readonly zh: "继续进行 CouchDB 设置"; + readonly "zh-tw": "繼續進行 CouchDB 設定"; + }; + readonly "Continue to Peer-to-Peer only setup": { + readonly def: "Continue to Peer-to-Peer only setup"; + readonly es: "Continuar con la configuración solo Peer-to-Peer"; + readonly ja: "Peer-to-Peer 専用設定へ進む"; + readonly ko: "Peer-to-Peer 전용 설정으로 계속"; + readonly ru: "Перейти к настройке только Peer-to-Peer"; + readonly zh: "继续进行仅 Peer-to-Peer 设置"; + readonly "zh-tw": "繼續進行僅 Peer-to-Peer 設定"; + }; + readonly "Continue to S3/MinIO/R2 setup": { + readonly def: "Continue to S3/MinIO/R2 setup"; + readonly es: "Continuar con la configuración de S3/MinIO/R2"; + readonly ja: "S3/MinIO/R2 設定へ進む"; + readonly ko: "S3/MinIO/R2 설정으로 계속"; + readonly ru: "Перейти к настройке S3/MinIO/R2"; + readonly zh: "继续进行 S3/MinIO/R2 设置"; + readonly "zh-tw": "繼續進行 S3/MinIO/R2 設定"; + }; + readonly Copy: { + readonly def: "Copy"; + readonly es: "Copiar"; + readonly ja: "コピー"; + readonly ko: "복사"; + readonly ru: "Копировать"; + readonly zh: "复制"; + readonly "zh-tw": "複製"; + }; + readonly "Copy Report to clipboard": { + readonly def: "Copy Report to clipboard"; + readonly fr: "Copier le rapport dans le presse-papiers"; + readonly he: "העתק דו\"ח ללוח"; + readonly ja: "レポートをクリップボードにコピー"; + readonly ko: "보고서를 클립보드에 복사"; + readonly ru: "Копировать отчёт в буфер обмена"; + readonly zh: "将报告复制到剪贴板"; + readonly "zh-tw": "將報告複製到剪貼簿"; + }; + readonly "CouchDB Connection Tweak": { + readonly def: "CouchDB Connection Tweak"; + readonly es: "Ajustes de conexión de CouchDB"; + readonly ja: "CouchDB 接続の調整"; + readonly ko: "CouchDB 연결 조정"; + readonly ru: "Настройки подключения CouchDB"; + readonly zh: "CouchDB 连接调优"; + readonly "zh-tw": "CouchDB 連線調校"; + }; + readonly "Cross-platform": { + readonly def: "Cross-platform"; + readonly es: "Multiplataforma"; + readonly ja: "クロスプラットフォーム"; + readonly ko: "크로스 플랫폼"; + readonly ru: "Кроссплатформенные"; + readonly zh: "跨平台"; + readonly "zh-tw": "跨平台"; + }; + readonly "Current adapter: {adapter}": { + readonly def: "Current adapter: {adapter}"; + readonly es: "Adaptador actual: {adapter}"; + readonly ja: "現在のアダプター: {adapter}"; + readonly ko: "현재 어댑터: {adapter}"; + readonly ru: "Текущий адаптер: {adapter}"; + readonly zh: "当前适配器:{adapter}"; + readonly "zh-tw": "目前的適配器:{adapter}"; + }; + readonly "Customization Sync": { + readonly def: "Customization Sync"; + readonly es: "Sincronización de personalización"; + readonly ja: "カスタマイズ同期"; + readonly ko: "사용자 지정 동기화"; + readonly ru: "Синхронизация настроек"; + readonly zh: "自定义同步"; + readonly "zh-tw": "自訂同步"; + }; + readonly "Customization Sync (Beta3)": { + readonly def: "Customization Sync (Beta3)"; + readonly es: "Sincronización de personalización (Beta3)"; + readonly ja: "カスタマイズ同期 (Beta3)"; + readonly ko: "사용자 지정 동기화 (Beta3)"; + readonly ru: "Синхронизация настроек (Beta3)"; + readonly zh: "自定义同步(Beta3)"; + readonly "zh-tw": "自訂同步(Beta3)"; + }; + readonly "Data Compression": { + readonly def: "Data Compression"; + readonly es: "Compresión de datos"; + readonly fr: "Compression des données"; + readonly he: "דחיסת נתונים"; + readonly ja: "データ圧縮"; + readonly ko: "데이터 압축"; + readonly ru: "Сжатие данных"; + readonly zh: "数据压缩"; + readonly "zh-tw": "資料壓縮"; + }; + readonly "Database -> Storage": { + readonly def: "Database -> Storage"; + readonly "zh-tw": "資料庫 -> 儲存空間"; + }; + readonly "Database Adapter": { + readonly def: "Database Adapter"; + readonly es: "Adaptador de base de datos"; + readonly ja: "データベースアダプター"; + readonly ko: "데이터베이스 어댑터"; + readonly ru: "Адаптер базы данных"; + readonly zh: "数据库适配器"; + readonly "zh-tw": "資料庫適配器"; + }; + readonly "Database Name": { + readonly def: "Database Name"; + readonly es: "Nombre de la base de datos"; + readonly fr: "Nom de la base de données"; + readonly he: "שם מסד נתונים"; + readonly ja: "データベース名"; + readonly ko: "데이터베이스 이름"; + readonly ru: "Имя базы данных"; + readonly zh: "数据库名称"; + readonly "zh-tw": "資料庫名稱"; + }; + readonly "Database suffix": { + readonly def: "Database suffix"; + readonly es: "Sufijo de base de datos"; + readonly fr: "Suffixe de la base de données"; + readonly he: "סיומת מסד נתונים"; + readonly ja: "データベースの接尾辞(suffix)"; + readonly ko: "데이터베이스 접미사"; + readonly ru: "Суффикс базы данных"; + readonly zh: "数据库后缀"; + readonly "zh-tw": "資料庫後綴"; + }; + readonly Default: { + readonly def: "Default"; + readonly es: "Predeterminado"; + readonly ja: "デフォルト"; + readonly ko: "기본값"; + readonly ru: "По умолчанию"; + readonly zh: "默认"; + readonly "zh-tw": "預設"; + }; + readonly "Delay conflict resolution of inactive files": { + readonly def: "Delay conflict resolution of inactive files"; + readonly es: "Retrasar resolución de conflictos en archivos inactivos"; + readonly fr: "Différer la résolution des conflits pour les fichiers inactifs"; + readonly he: "עכב פתרון קונפליקטים לקבצים לא פעילים"; + readonly ja: "非アクティブなファイルは、競合解決を先送りする"; + readonly ko: "비활성 파일의 충돌 해결 지연"; + readonly ru: "Отложить разрешение конфликтов для неактивных файлов"; + readonly zh: "推迟解决不活动文件"; + readonly "zh-tw": "延後處理非活動檔案的衝突"; + }; + readonly "Delay merge conflict prompt for inactive files.": { + readonly def: "Delay merge conflict prompt for inactive files."; + readonly es: "Retrasar aviso de fusión para archivos inactivos"; + readonly fr: "Différer l'invite de conflit de fusion pour les fichiers inactifs."; + readonly he: "עכב הצגת בקשת מיזוג לקבצים לא פעילים."; + readonly ja: "非アクティブなファイルの競合解決のプロンプトの表示を遅延させる"; + readonly ko: "비활성 파일의 병합 충돌 프롬프트 지연."; + readonly ru: "Отложить запрос конфликта слияния для неактивных файлов."; + readonly zh: "推迟手动解决不活动文件"; + readonly "zh-tw": "延後顯示非活動檔案的合併衝突提示。"; + }; + readonly Delete: { + readonly def: "Delete"; + readonly es: "Eliminar"; + readonly ja: "削除"; + readonly ko: "삭제"; + readonly ru: "Удалить"; + readonly zh: "删除"; + readonly "zh-tw": "刪除"; + }; + readonly "Delete all customization sync data": { + readonly def: "Delete all customization sync data"; + readonly es: "Eliminar todos los datos de sincronización de personalización"; + readonly ja: "カスタマイズ同期データをすべて削除"; + readonly ko: "모든 사용자 정의 동기화 데이터 삭제"; + readonly ru: "Удалить все данные синхронизации настроек"; + readonly zh: "删除所有自定义同步数据"; + readonly "zh-tw": "刪除所有自訂同步資料"; + }; + readonly "Delete all data on the remote server.": { + readonly def: "Delete all data on the remote server."; + readonly es: "Eliminar todos los datos del servidor remoto."; + readonly ja: "リモートサーバー上のすべてのデータを削除します。"; + readonly ko: "원격 서버의 모든 데이터를 삭제합니다."; + readonly ru: "Удалить все данные на удалённом сервере."; + readonly zh: "删除远端服务器上的所有数据。"; + readonly "zh-tw": "刪除遠端伺服器上的所有資料。"; + }; + readonly "Delete local database to reset or uninstall Self-hosted LiveSync": { + readonly def: "Delete local database to reset or uninstall Self-hosted LiveSync"; + readonly es: "Eliminar la base de datos local para restablecer o desinstalar Self-hosted LiveSync"; + readonly ja: "Self-hosted LiveSync をリセットまたはアンインストールするため、ローカルデータベースを削除"; + readonly ko: "Self-hosted LiveSync를 초기화하거나 제거하기 위해 로컬 데이터베이스를 삭제"; + readonly ru: "Удалить локальную базу данных, чтобы сбросить или удалить Self-hosted LiveSync"; + readonly zh: "删除本地数据库以重置或卸载 Self-hosted LiveSync"; + readonly "zh-tw": "刪除本機資料庫以重設或解除安裝 Self-hosted LiveSync"; + }; + readonly "Delete old metadata of deleted files on start-up": { + readonly def: "Delete old metadata of deleted files on start-up"; + readonly es: "Borrar metadatos viejos al iniciar"; + readonly fr: "Supprimer les anciennes métadonnées des fichiers effacés au démarrage"; + readonly he: "מחק מטה-נתונים ישנים של קבצים שנמחקו בעת הפעלה"; + readonly ja: "削除済みデータのメタデータをクリーンナップする"; + readonly ko: "시작 시 삭제된 파일의 오래된 메타데이터 삭제"; + readonly ru: "Удалять старые метаданные удалённых файлов при запуске"; + readonly zh: "启动时删除已删除文件的旧元数据"; + readonly "zh-tw": "啟動時刪除已刪除檔案的舊中繼資料"; + }; + readonly "Delete Remote Configuration": { + readonly def: "Delete Remote Configuration"; + readonly es: "Eliminar configuración remota"; + readonly ja: "リモート設定を削除"; + readonly ko: "원격 구성 삭제"; + readonly ru: "Удалить удалённую конфигурацию"; + readonly zh: "删除远端配置"; + readonly "zh-tw": "刪除遠端設定"; + }; + readonly "Delete remote configuration '{name}'?": { + readonly def: "Delete remote configuration '{name}'?"; + readonly es: "¿Eliminar la configuración remota '{name}'?"; + readonly ja: "リモート設定 '{name}' を削除しますか?"; + readonly ko: "'{name}' 원격 구성을 삭제할까요?"; + readonly ru: "Удалить удалённую конфигурацию '{name}'?"; + readonly zh: "要删除远端配置“{name}”吗?"; + readonly "zh-tw": "要刪除遠端設定「{name}」嗎?"; + }; + readonly desktop: { + readonly def: "desktop"; + readonly es: "equipo de escritorio"; + readonly ja: "デスクトップ"; + readonly ko: "데스크톱"; + readonly ru: "рабочий стол"; + readonly zh: "桌面设备"; + readonly "zh-tw": "桌面裝置"; + }; + readonly Developer: { + readonly def: "Developer"; + readonly es: "Desarrollador"; + readonly ja: "開発者"; + readonly ko: "개발자"; + readonly ru: "Разработчик"; + readonly zh: "开发者"; + readonly "zh-tw": "開發者"; + }; + readonly Device: { + readonly def: "Device"; + readonly ja: "デバイス"; + readonly ko: "기기"; + readonly ru: "Устройство"; + readonly zh: "设备"; + readonly "zh-tw": "裝置"; + }; + readonly "Device name": { + readonly def: "Device name"; + readonly es: "Nombre del dispositivo"; + readonly fr: "Nom de l'appareil"; + readonly he: "שם מכשיר"; + readonly ja: "デバイス名"; + readonly ko: "기기 이름"; + readonly ru: "Имя устройства"; + readonly zh: "设备名称"; + readonly "zh-tw": "裝置名稱"; + }; + readonly "Device Setup Method": { + readonly def: "Device Setup Method"; + readonly es: "Método de configuración del dispositivo"; + readonly ja: "端末の設定方法"; + readonly ko: "장치 설정 방법"; + readonly ru: "Способ настройки устройства"; + readonly zh: "设备设置方式"; + readonly "zh-tw": "裝置設定方式"; + }; + readonly "dialog.yourLanguageAvailable": { + readonly def: "Self-hosted LiveSync had translations for your language, so the %{Display language} setting was enabled.\n\nNote: Not all messages are translated. We are waiting for your contributions!\nNote 2: If you create an Issue, **please revert to Default** and then take screenshots, messages and logs. This can be done in the setting dialogue.\nMay you find it easy to use!"; + readonly fr: "Self-hosted LiveSync dispose d'une traduction pour votre langue, le paramètre %{Display language} a donc été activé.\n\nNote : Tous les messages ne sont pas traduits. Nous attendons vos contributions !\nNote 2 : Si vous créez un ticket, **veuillez revenir à Par défaut** puis prendre des captures d'écran, messages et journaux. Cela peut être fait dans la boîte de dialogue des paramètres.\nBonne utilisation !"; + readonly he: "ל-Self-hosted LiveSync יש תרגום לשפתך, ולכן הגדרת %{Display language} הופעלה.\n\nהערה: לא כל ההודעות מתורגמות. אנחנו ממתינים לתרומותיך!\nהערה 2: אם אתה פותח Issue, **אנא חזור ל-%{lang-def}** ואז צלם צילומי מסך, הודעות ויומנים. ניתן לעשות זאת בדיאלוג ההגדרות.\nנקווה שתמצא/י את הפלאגין נוח לשימוש!"; + readonly ja: "Self-hosted LiveSync に設定されている言語の翻訳がありましたので、インターフェースの表示言語が適用されました。\n\n注意: 全てのメッセージは翻訳されていません。あなたの貢献をお待ちしています!\nGithubにIssueを作成する際には、 インターフェースの表示言語 を一旦 Default に戻してから、スクショやメッセージ、ログを収集してください。これは設定から変更できます。\n\n便利に使用できれば幸いです。"; + readonly ko: "Self-hosted LiveSync에서 귀하의 언어로 번역을 제공하므로 %{Display language} 설정이 활성화되었습니다.\n\n참고: 모든 메시지가 번역되지는 않습니다. 귀하의 기여를 기다리고 있습니다!\n참고 2: 이슈를 생성하는 경우 **Default로 되돌린 후** 스크린샷, 메시지, 로그를 가져와 주세요. 이는 설정 대화 상자에서 할 수 있습니다.\n간편하게 사용하실 수 있었으면 좋겠습니다!"; + readonly ru: "Self-hosted LiveSync имеет переводы для вашего языка, поэтому была включена настройка языка Display language.\n\nПримечание: Не все сообщения переведены. Мы ждём ваших предложений!\nПримечание 2: При создании Issue, пожалуйста, вернитесь к lang-def, затем сделайте скриншоты, сообщения и логи. Это можно сделать в настройках.\nНадеемся, вам будет удобно использовать!"; + readonly zh: "Self-hosted LiveSync已提供您语言的翻译,因此启用了%{Display language}\n\n注意:并非所有消息都已翻译。我们期待您的贡献!\n注意 2:若您创建问题报告, **请切换回Default** ,然后截取屏幕截图、消息和日志,此操作可在设置对话框中完成\n愿您使用顺心!"; + readonly "zh-tw": "Self-hosted LiveSync 已提供你目前語言的翻譯,因此已啟用顯示語言設定。\n\n注意:並非所有訊息都已完成翻譯,歡迎協助補充!\n注意 2:如果你要回報問題,請先切回預設語言,再附上截圖、訊息與日誌。\n\n希望你使用愉快!"; + }; + readonly "dialog.yourLanguageAvailable.btnRevertToDefault": { + readonly def: "Keep Default"; + readonly fr: "Conserver Par défaut"; + readonly he: "השאר %{lang-def}"; + readonly ja: "Keep Default"; + readonly ko: "Default 유지"; + readonly ru: "Оставить lang-def"; + readonly zh: "保持Default"; + readonly "zh-tw": "恢復為預設語言"; + }; + readonly "dialog.yourLanguageAvailable.Title": { + readonly def: " Translation is available!"; + readonly fr: " Une traduction est disponible !"; + readonly he: " תרגום זמין!"; + readonly ja: "翻訳が利用可能です!"; + readonly ko: " 번역을 사용할 수 있습니다!"; + readonly ru: "Доступен перевод!"; + readonly zh: " 翻译可用!"; + readonly "zh-tw": "已提供你的語言翻譯!"; + }; + readonly "Disables all synchronization and restart.": { + readonly def: "Disables all synchronization and restart."; + readonly es: "Desactiva toda la sincronización y reinicia la aplicación."; + readonly ja: "すべての同期を無効にして再起動します。"; + readonly ko: "모든 동기화를 비활성화하고 재시작합니다."; + readonly ru: "Отключает всю синхронизацию и перезапускает приложение."; + readonly zh: "禁用所有同步并重新启动。"; + readonly "zh-tw": "停用所有同步並重新啟動。"; + }; + readonly "Disables logging, only shows notifications. Please disable if you report an issue.": { + readonly def: "Disables logging, only shows notifications. Please disable if you report an issue."; + readonly es: "Desactiva registros, solo muestra notificaciones. Desactívelo si reporta un problema."; + readonly fr: "Désactive la journalisation, n'affiche que les notifications. Veuillez désactiver si vous signalez un problème."; + readonly he: "מכבה רישום יומן, מציג התראות בלבד. אנא כבה אם אתה מדווח על בעיה."; + readonly ja: "ログを無効にし、通知のみを表示します。Issueを報告する場合は無効にしてください。"; + readonly ko: "로깅을 비활성화하고 알림만 표시합니다. 문제를 신고하는 경우 비활성화해 주세요."; + readonly ru: "Отключает логирование, показывает только уведомления. Пожалуйста, отключите при сообщении о проблеме."; + readonly zh: "禁用日志记录,仅显示通知。如果您报告问题,请禁用此选项"; + readonly "zh-tw": "停用日誌記錄,只顯示通知。如果你要回報問題,請關閉此選項。"; + }; + readonly "Display Language": { + readonly def: "Display Language"; + readonly es: "Idioma de visualización"; + readonly fr: "Langue d'affichage"; + readonly he: "שפת תצוגה"; + readonly ja: "インターフェースの表示言語"; + readonly ko: "표시 언어"; + readonly ru: "Язык интерфейса"; + readonly zh: "显示语言"; + readonly "zh-tw": "顯示語言"; + }; + readonly "Display name": { + readonly def: "Display name"; + readonly es: "Nombre para mostrar"; + readonly ja: "表示名"; + readonly ko: "표시 이름"; + readonly ru: "Отображаемое имя"; + readonly zh: "显示名称"; + readonly "zh-tw": "顯示名稱"; + }; + readonly "Do not check configuration mismatch before replication": { + readonly def: "Do not check configuration mismatch before replication"; + readonly es: "No verificar incompatibilidades antes de replicar"; + readonly fr: "Ne pas vérifier les incohérences de configuration avant la réplication"; + readonly he: "אל תבדוק אי-התאמה בתצורה לפני שכפול"; + readonly ja: "サーバーから同期する前に設定の不一致を確認しない"; + readonly ko: "복제 전 구성 불일치 확인 안 함"; + readonly ru: "Не проверять несовпадение конфигурации перед репликацией"; + readonly zh: "在复制前不检查配置不匹配"; + readonly "zh-tw": "複寫前不檢查設定是否不一致"; + }; + readonly "Do not keep metadata of deleted files.": { + readonly def: "Do not keep metadata of deleted files."; + readonly es: "No conservar metadatos de archivos borrados"; + readonly fr: "Ne pas conserver les métadonnées des fichiers supprimés."; + readonly he: "אל תשמור מטה-נתונים של קבצים שנמחקו."; + readonly ja: "削除済みファイルのメタデータを保持しない"; + readonly ko: "삭제된 파일의 메타데이터를 보관하지 않습니다."; + readonly ru: "Не хранить метаданные удалённых файлов."; + readonly zh: "不保留已删除文件的元数据 "; + readonly "zh-tw": "不保留已刪除檔案的中繼資料。"; + }; + readonly "Do not split chunks in the background": { + readonly def: "Do not split chunks in the background"; + readonly es: "No dividir chunks en segundo plano"; + readonly fr: "Ne pas fragmenter en arrière-plan"; + readonly he: "אל תפצל נתחים ברקע"; + readonly ja: "バックグラウンドでチャンクを分割しない"; + readonly ko: "백그라운드에서 청크 분할 안 함"; + readonly ru: "Не разделять чанки в фоновом режиме"; + readonly zh: "不在后台分割 chunks"; + readonly "zh-tw": "不在背景分割 chunks"; + }; + readonly "Do not use internal API": { + readonly def: "Do not use internal API"; + readonly es: "No usar API interna"; + readonly fr: "Ne pas utiliser l'API interne"; + readonly he: "אל תשתמש ב-API פנימי"; + readonly ja: "内部APIを使用しない"; + readonly ko: "내부 API 사용 안 함"; + readonly ru: "Не использовать внутренний API"; + readonly zh: "不使用内部 API"; + readonly "zh-tw": "不使用內部 API"; + }; + readonly "Doctor.Button.DismissThisVersion": { + readonly def: "No, and do not ask again until the next release"; + readonly fr: "Non, et ne plus demander jusqu'à la prochaine version"; + readonly he: "לא, ואל תשאל שוב עד לגרסה הבאה"; + readonly ja: "いいえ、次のリリースまで再度確認しない"; + readonly ko: "아니요, 다음 릴리스까지 다시 묻지 않음"; + readonly ru: "Нет, и не спрашивать до следующего выпуска"; + readonly zh: "拒绝,并且直到下个版本前不再询问"; + }; + readonly "Doctor.Button.Fix": { + readonly def: "Fix it"; + readonly fr: "Corriger"; + readonly he: "תקן"; + readonly ja: "修正する"; + readonly ko: "수정"; + readonly ru: "Исправить"; + readonly zh: "修复"; + }; + readonly "Doctor.Button.FixButNoRebuild": { + readonly def: "Fix it but no rebuild"; + readonly fr: "Corriger mais sans reconstruction"; + readonly he: "תקן ללא בנייה מחדש"; + readonly ja: "修正するが再構築はしない"; + readonly ko: "수정하지만 재구축하지 않음"; + readonly ru: "Исправить без перестроения"; + readonly zh: "修复但不重建"; + }; + readonly "Doctor.Button.No": { + readonly def: "No"; + readonly fr: "Non"; + readonly he: "לא"; + readonly ja: "いいえ"; + readonly ko: "아니요"; + readonly ru: "Нет"; + readonly zh: "拒绝"; + }; + readonly "Doctor.Button.Skip": { + readonly def: "Leave it as is"; + readonly fr: "Laisser tel quel"; + readonly he: "השאר כפי שהוא"; + readonly ja: "そのままにする"; + readonly ko: "그대로 두기"; + readonly ru: "Оставить как есть"; + readonly zh: "保持不变"; + }; + readonly "Doctor.Button.Yes": { + readonly def: "Yes"; + readonly fr: "Oui"; + readonly he: "כן"; + readonly ja: "はい"; + readonly ko: "예"; + readonly ru: "Да"; + readonly zh: "确定"; + }; + readonly "Doctor.Dialogue.Main": { + readonly def: "Hi! Config Doctor has been activated because of ${activateReason}!\nAnd, unfortunately some configurations were detected as potential problems.\nPlease be assured. Let's solve them one by one.\n\nTo let you know ahead of time, we will ask you about the following items.\n\n${issues}\n\nShall we get started?"; + readonly fr: "Bonjour ! Config Doctor a été activé en raison de ${activateReason} !\nEt, malheureusement, certaines configurations ont été détectées comme des problèmes potentiels.\nPas d'inquiétude. Résolvons-les un par un.\n\nPour information, nous allons vous interroger sur les éléments suivants.\n\n${issues}\n\nVoulez-vous commencer ?"; + readonly he: "שלום! רופא התצורה הופעל בגלל ${activateReason}!\nולמרבה הצער, זוהו תצורות שעשויות להיות בעייתיות.\nהיה רגוע/ה. בואו נפתור אותן אחת אחת.\n\nלידיעתך מראש, נשאל אותך על הפריטים הבאים.\n\n${issues}\n\nהאם להתחיל?"; + readonly ja: "こんにちは!${activateReason}のため、設定診断ツールが起動しました!\n残念ながら、いくつかの設定が潜在的な問題として検出されました。\nご安心ください。一つずつ解決していきましょう。\n\n事前にお知らせしますと、以下の項目についてお尋ねします。\n\n${issues}\n\n始めていいですか?"; + readonly ko: "안녕하세요! ${activateReason} 로 인해 구성 진단 마법사가 활성화되었습니다!\n그리고 일부 구성이 잠재적인 문제로 감지되었습니다.\n안심하세요. 하나씩 해결해 봅시다.\n\n대상 항목은 다음과 같습니다.\n\n${issues}\n\n시작하시겠습니까?"; + readonly ru: "Привет! Диагностика настроек активирована из-за activateReason!\nК сожалению, некоторые настройки были обнаружены как потенциальные проблемы.\nНе волнуйтесь. Давайте решим их по очереди.\n\nСообщаем вам заранее, мы спросим о следующих пунктах.\n\nissues\n\nНачнём?"; + readonly zh: "您好!配置医生已根据您的要求启动(感谢您)!!遗憾的是,检测到部分配置存在潜在问题。请放心,我们将逐一解决这些问题。\n\n提前告知您,我们将就以下事项进行确认:\n\n为数据块计算修订版本(此前行为)\n增强块大小\n\n我们开始处理吗?"; + }; + readonly "Doctor.Dialogue.MainFix": { + readonly def: "\n## ${name}\n\n| Current | Ideal |\n|:---:|:---:|\n| ${current} | ${ideal} |\n\n**Recommendation Level:** ${level}\n\n### Why this has been detected?\n\n${reason}\n\n${note}\n\nFix this to the ideal value?"; + readonly fr: "\n## ${name}\n\n| Actuel | Idéal |\n|:---:|:---:|\n| ${current} | ${ideal} |\n\n**Niveau de recommandation :** ${level}\n\n### Pourquoi ceci a-t-il été détecté ?\n\n${reason}\n\n${note}\n\nCorriger à la valeur idéale ?"; + readonly he: "\n## ${name}\n\n| נוכחי | אידאלי |\n|:---:|:---:|\n| ${current} | ${ideal} |\n\n**רמת המלצה:** ${level}\n\n### מדוע זה זוהה?\n\n${reason}\n\n${note}\n\nלתקן לערך האידאלי?"; + readonly ja: "\n## ${name}\n\n| 現在の値 | 理想値 |\n|:---:|:---:|\n| ${current} | ${ideal} |\n\n**推奨レベル:** ${level}\n\n### 診断理由?\n\n${reason}\n\n${note}\n\nこれを理想値に修正しますか?"; + readonly ko: "**구성 이름:** `${name}`\n**현재 값:** `${current}`, **이상적인 값:** `${ideal}`\n**권장 수준:** ${level}\n**왜 이것이 감지되었나요?**\n${reason}\n\n\n${note}\n\n이상적인 값으로 수정하시겠습니까?"; + readonly ru: "name\n\n| Текущее | Идеальное |\n|:---:|:---:|\n| current | ideal |\n\n**Уровень рекомендации:** level\n\n### Почему это было обнаружено?\n\nreason\n\nnote\n\nИсправить на идеальное значение?"; + readonly zh: "\n## ${name}\n\n| Current | Ideal |\n|:---:|:---:|\n| ${current} | ${ideal} |\n\n**Recommendation Level:** ${level}\n\n### Why this has been detected?\n\n${reason}\n\n${note}\n\nFix this to the ideal value?"; + }; + readonly "Doctor.Dialogue.Title": { + readonly def: "Self-hosted LiveSync Config Doctor"; + readonly fr: "Docteur Config Self-hosted LiveSync"; + readonly he: "Self-hosted LiveSync Config Doctor"; + readonly ja: "Self-hosted LiveSync 設定診断ツール"; + readonly ko: "Self-hosted LiveSync 구성 진단 마법사"; + readonly ru: "Диагностика Self-hosted LiveSync"; + readonly zh: "Self-hosted LiveSync 配置诊断"; + }; + readonly "Doctor.Dialogue.TitleAlmostDone": { + readonly def: "Almost done!"; + readonly fr: "Presque terminé !"; + readonly he: "כמעט סיימנו!"; + readonly ja: "あと少しです!"; + readonly ko: "거의 완료되었습니다!"; + readonly ru: "Почти готово!"; + readonly zh: "全部完成!"; + }; + readonly "Doctor.Dialogue.TitleFix": { + readonly def: "Fix issue ${current}/${total}"; + readonly fr: "Corriger le problème ${current}/${total}"; + readonly he: "תקן בעיה ${current}/${total}"; + readonly ja: "問題の修正 ${current}/${total}"; + readonly ko: "문제 해결 ${current}/${total}"; + readonly ru: "Исправление проблемы current/total"; + readonly zh: "修复问题 ${current}/${total}"; + }; + readonly "Doctor.Level.Must": { + readonly def: "Must"; + readonly fr: "Obligatoire"; + readonly he: "חובה"; + readonly ja: "必須"; + readonly ko: "필수"; + readonly ru: "Обязательно"; + readonly zh: "必须"; + }; + readonly "Doctor.Level.Necessary": { + readonly def: "Necessary"; + readonly fr: "Nécessaire"; + readonly he: "נדרש"; + readonly ja: "必要"; + readonly ko: "필수"; + readonly ru: "Необходимо"; + readonly zh: "必要"; + }; + readonly "Doctor.Level.Optional": { + readonly def: "Optional"; + readonly fr: "Optionnel"; + readonly he: "אופציונלי"; + readonly ja: "任意"; + readonly ko: "선택사항"; + readonly ru: "Опционально"; + readonly zh: "可选"; + }; + readonly "Doctor.Level.Recommended": { + readonly def: "Recommended"; + readonly fr: "Recommandé"; + readonly he: "מומלץ"; + readonly ja: "推奨"; + readonly ko: "권장"; + readonly ru: "Рекомендуется"; + readonly zh: "推荐"; + }; + readonly "Doctor.Message.NoIssues": { + readonly def: "No issues detected!"; + readonly fr: "Aucun problème détecté !"; + readonly he: "לא זוהו בעיות!"; + readonly ja: "問題は検出されませんでした!"; + readonly ko: "문제가 감지되지 않았습니다!"; + readonly ru: "Проблем не обнаружено!"; + readonly zh: "未发现问题!"; + }; + readonly "Doctor.Message.RebuildLocalRequired": { + readonly def: "Attention! A local database rebuild is required to apply this!"; + readonly fr: "Attention ! Une reconstruction de la base locale est requise pour appliquer ceci !"; + readonly he: "שים לב! נדרשת בנייה מחדש של מסד הנתונים המקומי כדי להחיל זאת!"; + readonly ja: "注意!これを適用するにはローカルデータベースの再構築が必要です!"; + readonly ko: "주의! 이를 적용하려면 로컬 데이터베이스 재구축이 필요합니다!"; + readonly ru: "Внимание! Для применения требуется перестроение локальной базы данных!"; + readonly zh: "注意!需要重建本地数据库以应用此项!"; + }; + readonly "Doctor.Message.RebuildRequired": { + readonly def: "Attention! A rebuild is required to apply this!"; + readonly fr: "Attention ! Une reconstruction est requise pour appliquer ceci !"; + readonly he: "שים לב! נדרשת בנייה מחדש כדי להחיל זאת!"; + readonly ja: "注意!これを適用するには再構築が必要です!"; + readonly ko: "주의! 이를 적용하려면 재구축이 필요합니다!"; + readonly ru: "Внимание! Для применения требуется перестроение!"; + readonly zh: "注意!需要重建才能应用此项!"; + }; + readonly "Doctor.Message.SomeSkipped": { + readonly def: "We left some issues as is. Shall I ask you again on next startup?"; + readonly fr: "Nous avons laissé certains problèmes en l'état. Dois-je vous demander à nouveau au prochain démarrage ?"; + readonly he: "השארנו כמה בעיות כפי שהן. האם לשאול שוב בהפעלה הבאה?"; + readonly ja: "いくつかの問題をそのままにしました。次回起動時に再度確認しますか?"; + readonly ko: "일부 문제를 그대로 두었습니다. 다음 시작 시 다시 질문할까요?"; + readonly ru: "Некоторые проблемы оставлены как есть. Спросить снова при следующем запуске?"; + readonly zh: "我们将某些问题留给了以后处理。是否要在下次启动时再次询问您?"; + }; + readonly "Doctor.RULES.E2EE_V02500.REASON": { + readonly def: "The End-to-End Encryption has got now more robust and faster. Also because, the previous E2EE was found to be compromised in a re-conducted code review. It should be applied as soon as possible. Really apologises for your inconvenience. And, this setting is not forward compatible. All synchronised devices must be updated to v0.25.0 or higher. Rebuilds are not required and will be converted from the new transfer to the new format, However, it is recommended to rebuild whenever possible."; + readonly fr: "Le chiffrement de bout en bout est désormais plus robuste et plus rapide. Aussi parce que le précédent E2EE s'est révélé compromis lors d'une nouvelle revue de code. Il doit être appliqué dès que possible. Nous nous excusons sincèrement pour la gêne occasionnée. Ce paramètre n'est pas compatible avec les versions antérieures. Tous les appareils synchronisés doivent être mis à jour en v0.25.0 ou supérieur. Les reconstructions ne sont pas requises et seront converties du nouveau transfert vers le nouveau format. Il est toutefois recommandé de reconstruire dans la mesure du possible."; + readonly he: "ההצפנה מקצה לקצה עודכנה לגרסה חזקה ומהירה יותר. בנוסף, בסקירת קוד שנערכה מחדש הוסבר שההצפנה הקודמת נפרצת. יש להחיל זאת בהקדם האפשרי. מתנצלים על אי הנוחות. שים לב שהגדרה זו אינה תואמת לאחור. כל המכשירים המסונכרנים חייבים להיות מעודכנים לגרסה 0.25.0 ומעלה. אין צורך בבנייה מחדש והנתונים יומרו בהדרגה לפורמט החדש, אך מומלץ לבנות מחדש בהזדמנות הראשונה."; + readonly ja: "エンドツーエンド暗号化がより堅牢で高速になりました。また、以前のE2EEは再コードレビューにより脆弱性が発見されました。できるだけ早く適用することをお勧めします。ご不便をおかけして申し訳ありません。また、この設定は下位互換性がありません。すべての同期デバイスをv0.25.0以降にアップデートする必要があります。再構築は必須ではなく、新しい転送から新しいフォーマットに変換されますが、可能な限り再構築をお勧めします。"; + readonly ru: "Сквозное шифрование стало более надёжным и быстрым. Предыдущее E2EE было скомпрометировано. Следует применить как можно скорее."; + readonly zh: "The End-to-End Encryption has got now more robust and faster. Also because, the previous E2EE was found to be compromised in a re-conducted code review. It should be applied as soon as possible. Really apologises for your inconvenience. And, this setting is not forward compatible. All synchronised devices must be updated to v0.25.0 or higher. Rebuilds are not required and will be converted from the new transfer to the new format, However, it is recommended to rebuild whenever possible."; + }; + readonly "Document History": { + readonly def: "Document History"; + readonly "zh-tw": "文件歷程"; + }; + readonly Duplicate: { + readonly def: "Duplicate"; + readonly es: "Duplicar"; + readonly ja: "複製"; + readonly ko: "복제"; + readonly ru: "Дублировать"; + readonly zh: "复制"; + readonly "zh-tw": "複製"; + }; + readonly "Duplicate remote": { + readonly def: "Duplicate remote"; + readonly es: "Duplicar remoto"; + readonly ja: "リモート設定を複製"; + readonly ko: "원격 구성 복제"; + readonly ru: "Дублировать удалённую конфигурацию"; + readonly zh: "复制远端配置"; + readonly "zh-tw": "複製遠端設定"; + }; + readonly "E2EE Configuration": { + readonly def: "E2EE Configuration"; + readonly es: "Configuración de E2EE"; + readonly ja: "E2EE 設定"; + readonly ko: "E2EE 구성"; + readonly ru: "Конфигурация сквозного шифрования"; + readonly zh: "E2EE 配置"; + readonly "zh-tw": "E2EE 設定"; + }; + readonly "Edge case addressing (Behaviour)": { + readonly def: "Edge case addressing (Behaviour)"; + readonly es: "Tratamiento de casos límite (comportamiento)"; + readonly ja: "特殊なケースへの対応(動作)"; + readonly ko: "특수 상황 처리 (동작)"; + readonly ru: "Обработка особых случаев (поведение)"; + readonly zh: "边缘情况处理(行为)"; + readonly "zh-tw": "邊緣情況處理(行為)"; + }; + readonly "Edge case addressing (Database)": { + readonly def: "Edge case addressing (Database)"; + readonly es: "Tratamiento de casos límite (base de datos)"; + readonly ja: "特殊なケースへの対応(データベース)"; + readonly ko: "특수 상황 처리 (데이터베이스)"; + readonly ru: "Обработка особых случаев (база данных)"; + readonly zh: "边缘情况处理(数据库)"; + readonly "zh-tw": "邊緣情況處理(資料庫)"; + }; + readonly "Edge case addressing (Processing)": { + readonly def: "Edge case addressing (Processing)"; + readonly es: "Tratamiento de casos límite (procesamiento)"; + readonly ja: "特殊なケースへの対応(処理)"; + readonly ko: "특수 상황 처리 (처리)"; + readonly ru: "Обработка особых случаев (обработка)"; + readonly zh: "边缘情况处理(处理)"; + readonly "zh-tw": "邊緣情況處理(處理)"; + }; + readonly "Emergency restart": { + readonly def: "Emergency restart"; + readonly es: "Reinicio de emergencia"; + readonly ja: "緊急再起動"; + readonly ko: "긴급 재시작"; + readonly ru: "Аварийный перезапуск"; + readonly zh: "紧急重启"; + readonly "zh-tw": "緊急重新啟動"; + }; + readonly "Enable advanced features": { + readonly def: "Enable advanced features"; + readonly es: "Habilitar características avanzadas"; + readonly fr: "Activer les fonctionnalités avancées"; + readonly he: "הפעל תכונות מתקדמות"; + readonly ja: "高度な機能を有効にする"; + readonly ko: "고급 기능 활성화"; + readonly ru: "Включить расширенные функции"; + readonly zh: "启用高级功能"; + readonly "zh-tw": "啟用進階功能"; + }; + readonly "Enable customization sync": { + readonly def: "Enable customization sync"; + readonly es: "Habilitar sincronización de personalización"; + readonly fr: "Activer la synchronisation de personnalisation"; + readonly he: "הפעל סנכרון התאמה אישית"; + readonly ja: "カスタマイズ同期を有効"; + readonly ko: "사용자 설정 동기화 활성화"; + readonly ru: "Включить синхронизацию настроек"; + readonly zh: "启用自定义同步"; + readonly "zh-tw": "啟用自訂同步"; + }; + readonly "Enable Developers' Debug Tools.": { + readonly def: "Enable Developers' Debug Tools."; + readonly es: "Habilitar herramientas de depuración"; + readonly fr: "Activer les outils de débogage pour développeurs."; + readonly he: "הפעל כלי ניפוי באגים למפתחים."; + readonly ja: "開発者用デバッグツールを有効にする"; + readonly ko: "개발자 디버그 도구 활성화"; + readonly ru: "Включить инструменты разработчика."; + readonly zh: "启用开发者调试工具 "; + readonly "zh-tw": "啟用開發者除錯工具。"; + }; + readonly "Enable edge case treatment features": { + readonly def: "Enable edge case treatment features"; + readonly es: "Habilitar manejo de casos límite"; + readonly fr: "Activer les fonctionnalités pour cas particuliers"; + readonly he: "הפעל תכונות לטיפול במקרי קצה"; + readonly ja: "エッジケース対応機能を有効にする"; + readonly ko: "특수 사례 처리 기능 활성화"; + readonly ru: "Включить функции обработки граничных случаев"; + readonly zh: "启用边缘情况处理功能"; + readonly "zh-tw": "啟用邊緣情況處理功能"; + }; + readonly "Enable poweruser features": { + readonly def: "Enable poweruser features"; + readonly es: "Habilitar funciones para usuarios avanzados"; + readonly fr: "Activer les fonctionnalités pour utilisateurs avancés"; + readonly he: "הפעל תכונות למשתמש מתקדם"; + readonly ja: "エキスパート機能を有効にする"; + readonly ko: "파워 유저 기능 활성화"; + readonly ru: "Включить функции для опытных пользователей"; + readonly zh: "启用高级用户功能"; + readonly "zh-tw": "啟用進階使用者功能"; + }; + readonly "Enable this if your Object Storage doesn't support CORS": { + readonly def: "Enable this if your Object Storage doesn't support CORS"; + readonly es: "Habilitar si su almacenamiento no soporta CORS"; + readonly fr: "Activer ceci si votre stockage objet ne prend pas en charge CORS"; + readonly he: "הפעל אם אחסון האובייקטים שלך לא תומך ב-CORS"; + readonly ja: "オブジェクトストレージがCORSをサポートしていない場合は有効にしてください"; + readonly ko: "객체 스토리지가 CORS를 지원하지 않는 경우 활성화하세요"; + readonly ru: "Включите, если ваше объектное хранилище не поддерживает CORS"; + readonly zh: "如果您的对象存储不支持 CORS,请启用此功能 "; + readonly "zh-tw": "如果你的物件儲存不支援 CORS,請啟用此選項"; + }; + readonly "Enable this option to automatically apply the most recent change to documents even when it conflicts": { + readonly def: "Enable this option to automatically apply the most recent change to documents even when it conflicts"; + readonly es: "Aplicar cambios recientes automáticamente aunque generen conflictos"; + readonly fr: "Activer cette option pour appliquer automatiquement la modification la plus récente aux documents même en cas de conflit"; + readonly he: "הפעל אפשרות זו כדי להחיל אוטומטית את השינוי האחרון במסמכים גם כשיש קונפליקט"; + readonly ja: "このオプションを有効にすると、競合があっても最新の変更を自動的にドキュメントに適用します"; + readonly ko: "이 옵션을 활성화하면 충돌이 있어도 문서에 가장 최근 변경 사항을 자동으로 적용합니다"; + readonly ru: "Включите эту опцию для автоматического применения последних изменений к документам даже при конфликте"; + readonly zh: "启用此选项可在文档冲突时自动应用最新的更改"; + readonly "zh-tw": "啟用此選項後,即使發生衝突也會自動套用文件的最新變更"; + }; + readonly "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": { + readonly def: "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended."; + readonly es: "Cifrar contenido en la base de datos remota. Se recomienda habilitar si usa la sincronización del plugin."; + readonly fr: "Chiffrer le contenu sur la base de données distante. Si vous utilisez la fonction de synchronisation du plugin, l'activation est recommandée."; + readonly he: "הצפן תוכן במסד הנתונים המרוחק. אם אתה משתמש בתכונת הסנכרון של התוסף, מומלץ להפעיל זאת."; + readonly ja: "リモートデータベースの暗号化(オンにすることを推奨)"; + readonly ko: "원격 데이터베이스의 내용을 암호화합니다. 플러그인의 동기화 기능을 사용하는 경우 활성화를 권장합니다."; + readonly ru: "Шифровать содержимое на удалённой базе данных. Рекомендуется включить при использовании функции синхронизации плагина."; + readonly zh: "加密远程数据库中的内容。如果您使用插件的同步功能,则建议启用此功能 "; + readonly "zh-tw": "加密遠端資料庫中的內容。如果你使用外掛的同步功能,建議啟用此選項。"; + }; + readonly "Encrypting sensitive configuration items": { + readonly def: "Encrypting sensitive configuration items"; + readonly es: "Cifrando elementos sensibles"; + readonly fr: "Chiffrement des éléments de configuration sensibles"; + readonly he: "הצפן פריטי תצורה רגישים"; + readonly ja: "機密性の高い設定項目の暗号化"; + readonly ko: "민감한 구성 항목 암호화"; + readonly ru: "Шифрование конфиденциальных настроек"; + readonly zh: "加密敏感配置项"; + readonly "zh-tw": "加密敏感設定項目"; + }; + readonly "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": { + readonly def: "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files."; + readonly es: "Frase de cifrado. Si la cambia, sobrescriba la base del servidor con los nuevos archivos cifrados."; + readonly fr: "Phrase secrète de chiffrement. Si modifiée, vous devriez écraser la base de données du serveur avec les nouveaux fichiers (chiffrés)."; + readonly he: "ביטוי סיסמה להצפנה. אם שונה, יש לדרוס את מסד הנתונים של השרת בקבצים החדשים (המוצפנים)."; + readonly ja: "暗号化パスフレーズ。変更した場合、新しい(暗号化された)ファイルでサーバーのデータベースを上書きする必要があります。"; + readonly ko: "패스프레이즈는 암호화에 사용되는 긴 암호 문구입니다. 변경한 경우, 암호화된 새 파일로 서버의 데이터베이스를 덮어써야 합니다."; + readonly ru: "Парольная фраза шифрования. При изменении нужно перезаписать базу данных сервера новыми (зашифрованными) файлами."; + readonly zh: "加密密码。如果更改,您应该用新的(加密的)文件覆盖服务器的数据库 "; + readonly "zh-tw": "加密密語。如果變更了它,你應以新的(已加密)檔案覆寫伺服器上的資料庫。"; + }; + readonly "End-to-End Encryption": { + readonly def: "End-to-End Encryption"; + readonly es: "Cifrado de extremo a extremo"; + readonly fr: "Chiffrement de bout en bout"; + readonly he: "הצפנה מקצה לקצה"; + readonly ja: "E2E暗号化"; + readonly ko: "종단간 암호화"; + readonly ru: "Сквозное шифрование"; + readonly zh: "端到端加密"; + readonly "zh-tw": "端對端加密"; + }; + readonly "Endpoint URL": { + readonly def: "Endpoint URL"; + readonly es: "URL del endpoint"; + readonly fr: "URL du point de terminaison"; + readonly he: "כתובת נקודת קצה (Endpoint URL)"; + readonly ja: "エンドポイントURL"; + readonly ko: "엔드포인트 URL"; + readonly ru: "URL конечной точки"; + readonly zh: "终端URL"; + readonly "zh-tw": "端點 URL"; + }; + readonly "Enhance chunk size": { + readonly def: "Enhance chunk size"; + readonly es: "Mejorar tamaño de chunks"; + readonly fr: "Améliorer la taille des fragments"; + readonly he: "הגדל גודל נתח"; + readonly ja: "チャンクサイズを最適化する"; + readonly ko: "청크 크기 향상"; + readonly ru: "Улучшить размер чанка"; + readonly zh: "增大块大小"; + readonly "zh-tw": "擴大 chunk 大小"; + }; + readonly "Enter Server Information": { + readonly def: "Enter Server Information"; + readonly es: "Introducir información del servidor"; + readonly ja: "サーバー情報の入力"; + readonly ko: "서버 정보 입력"; + readonly ru: "Ввести данные сервера"; + readonly zh: "输入服务器信息"; + readonly "zh-tw": "輸入伺服器資訊"; + }; + readonly "Enter the server information manually": { + readonly def: "Enter the server information manually"; + readonly es: "Introducir manualmente la información del servidor"; + readonly ja: "サーバー情報を手動で入力する"; + readonly ko: "서버 정보를 수동으로 입력"; + readonly ru: "Ввести данные сервера вручную"; + readonly zh: "手动输入服务器信息"; + readonly "zh-tw": "手動輸入伺服器資訊"; + }; + readonly Export: { + readonly def: "Export"; + readonly es: "Exportar"; + readonly ja: "エクスポート"; + readonly ko: "내보내기"; + readonly ru: "Экспорт"; + readonly zh: "导出"; + readonly "zh-tw": "匯出"; + }; + readonly "Failed to connect to remote for compaction.": { + readonly def: "Failed to connect to remote for compaction."; + readonly ja: "リモートデータベースに接続できず、コンパクションを実行できませんでした。"; + readonly ko: "압축을 위해 원격 데이터베이스에 연결하지 못했습니다."; + readonly ru: "Не удалось подключиться к удалённой базе данных для компакции."; + readonly zh: "无法连接到远程数据库以执行压缩。"; + readonly "zh-tw": "無法連線到遠端資料庫以執行壓縮。"; + }; + readonly "Failed to connect to remote for compaction. ${reason}": { + readonly def: "Failed to connect to remote for compaction. ${reason}"; + readonly ja: "リモートデータベースに接続できず、コンパクションを実行できませんでした。${reason}"; + readonly ko: "압축을 위해 원격 데이터베이스에 연결하지 못했습니다. ${reason}"; + readonly ru: "Не удалось подключиться к удалённой базе данных для компакции. ${reason}"; + readonly zh: "无法连接到远程数据库以执行压缩。${reason}"; + readonly "zh-tw": "無法連線到遠端資料庫以執行壓縮。${reason}"; + }; + readonly "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": { + readonly def: "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled."; + readonly ja: "Garbage Collection 前にワンショットレプリケーションを開始できませんでした。Garbage Collection はキャンセルされました。"; + readonly ko: "Garbage Collection 전에 일회성 복제를 시작하지 못했습니다. Garbage Collection을 취소합니다."; + readonly ru: "Не удалось запустить одноразовую репликацию перед Garbage Collection. Garbage Collection отменена."; + readonly zh: "无法在垃圾回收前启动一次性复制。垃圾回收已取消。"; + readonly "zh-tw": "無法在垃圾回收前啟動一次性複寫。垃圾回收已取消。"; + }; + readonly "Failed to start replication after Garbage Collection.": { + readonly def: "Failed to start replication after Garbage Collection."; + readonly ja: "Garbage Collection 後にレプリケーションを開始できませんでした。"; + readonly ko: "Garbage Collection 후 복제를 시작하지 못했습니다."; + readonly ru: "Не удалось запустить репликацию после Garbage Collection."; + readonly zh: "垃圾回收后无法启动复制。"; + readonly "zh-tw": "垃圾回收後無法啟動複寫。"; + }; + readonly Fetch: { + readonly def: "Fetch"; + readonly es: "Obtener"; + readonly ja: "取得"; + readonly ko: "가져오기"; + readonly ru: "Получить"; + readonly zh: "获取"; + readonly "zh-tw": "抓取"; + }; + readonly "Fetch chunks on demand": { + readonly def: "Fetch chunks on demand"; + readonly es: "Obtener chunks bajo demanda"; + readonly fr: "Récupérer les fragments à la demande"; + readonly he: "משוך נתחים לפי דרישה"; + readonly ja: "ユーザーのタイミングでチャンクの更新を確認する"; + readonly ko: "필요 시 청크 원격 가져오기"; + readonly ru: "Загружать чанки по требованию"; + readonly zh: "按需获取块"; + readonly "zh-tw": "按需抓取 chunks"; + }; + readonly "Fetch database with previous behaviour": { + readonly def: "Fetch database with previous behaviour"; + readonly es: "Obtener BD con comportamiento anterior"; + readonly fr: "Récupérer la base de données avec le comportement précédent"; + readonly he: "משוך מסד נתונים עם התנהגות קודמת"; + readonly ja: "以前の動作でデータベースを取得"; + readonly ko: "이전 동작으로 데이터베이스 가져오기"; + readonly ru: "Загрузить базу данных с предыдущим поведением"; + readonly zh: "使用以前的行为获取数据库"; + readonly "zh-tw": "以前一種行為抓取資料庫"; + }; + readonly "Fetch remote settings": { + readonly def: "Fetch remote settings"; + readonly es: "Obtener ajustes remotos"; + readonly ja: "リモート設定を取得"; + readonly ko: "원격 설정 가져오기"; + readonly ru: "Получить настройки с удалённого хранилища"; + readonly zh: "获取远端设置"; + readonly "zh-tw": "抓取遠端設定"; + }; + readonly "File to resolve conflict": { + readonly def: "File to resolve conflict"; + readonly es: "Archivo para resolver el conflicto"; + readonly ja: "競合を解決するファイル"; + readonly ko: "충돌을 해결할 파일"; + readonly ru: "Файл для разрешения конфликта"; + readonly zh: "选择要解决冲突的文件"; + readonly "zh-tw": "要解決衝突的檔案"; + }; + readonly "File to view History": { + readonly def: "File to view History"; + readonly "zh-tw": "要檢視歷程的檔案"; + }; + readonly Filename: { + readonly def: "Filename"; + readonly es: "Nombre de archivo"; + readonly fr: "Nom de fichier"; + readonly he: "שם קובץ"; + readonly ja: "ファイル名"; + readonly ko: "파일명"; + readonly ru: "Имя файла"; + readonly zh: "文件名"; + readonly "zh-tw": "檔名"; + }; + readonly "First, please select the option that best describes your current situation.": { + readonly def: "First, please select the option that best describes your current situation."; + readonly es: "Primero, seleccione la opción que describa mejor su situación actual。"; + readonly ja: "まず、現在の状況に最も近い項目を選択してください。"; + readonly ko: "먼저 현재 상황에 가장 잘 맞는 항목을 선택해 주세요。"; + readonly ru: "Сначала выберите вариант, который лучше всего описывает вашу текущую ситуацию。"; + readonly zh: "首先,请选择最符合你当前情况的选项。"; + readonly "zh-tw": "首先,請選擇最符合你目前情況的選項。"; + }; + readonly "Flag and restart": { + readonly def: "Flag and restart"; + readonly es: "Marcar y reiniciar"; + readonly ja: "フラグを立てて再起動"; + readonly ko: "표시 후 재시작"; + readonly ru: "Пометить и перезапустить"; + readonly zh: "标记后重启"; + readonly "zh-tw": "標記後重新啟動"; + }; + readonly "Forces the file to be synced when opened.": { + readonly def: "Forces the file to be synced when opened."; + readonly es: "Forzar sincronización al abrir archivo"; + readonly fr: "Force la synchronisation du fichier à son ouverture."; + readonly he: "מכריח סנכרון הקובץ בעת פתיחתו."; + readonly ja: "ファイルを開いたときに強制的に同期します。"; + readonly ko: "파일을 열 때 강제로 동기화합니다."; + readonly ru: "Принудительно синхронизировать файл при открытии."; + readonly zh: "打开文件时强制同步该文件 "; + readonly "zh-tw": "開啟檔案時強制同步該檔案。"; + }; + readonly "Fresh Start Wipe": { + readonly def: "Fresh Start Wipe"; + readonly es: "Borrado para reinicio completo"; + readonly ja: "初期化ワイプ"; + readonly ko: "새로 시작 지우기"; + readonly ru: "Полный сброс для чистого старта"; + readonly zh: "全新开始清除"; + readonly "zh-tw": "全新開始清除"; + }; + readonly "Garbage Collection cancelled by user.": { + readonly def: "Garbage Collection cancelled by user."; + readonly ja: "ユーザーによって Garbage Collection がキャンセルされました。"; + readonly ko: "사용자가 Garbage Collection을 취소했습니다."; + readonly ru: "Пользователь отменил Garbage Collection."; + readonly zh: "用户已取消垃圾回收。"; + readonly "zh-tw": "使用者已取消垃圾回收。"; + }; + readonly "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": { + readonly def: "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds."; + readonly ja: "Garbage Collection が完了しました。削除したチャンク: ${deletedChunks} / ${totalChunks}。所要時間: ${seconds} 秒。"; + readonly ko: "Garbage Collection이 완료되었습니다. 삭제된 청크: ${deletedChunks} / ${totalChunks}. 소요 시간: ${seconds}초."; + readonly ru: "Garbage Collection завершена. Удалено чанков: ${deletedChunks} / ${totalChunks}. Затраченное время: ${seconds} сек."; + readonly zh: "垃圾回收完成。已删除 chunks:${deletedChunks} / ${totalChunks}。耗时:${seconds} 秒。"; + readonly "zh-tw": "垃圾回收完成。已刪除 chunks:${deletedChunks} / ${totalChunks}。耗時:${seconds} 秒。"; + }; + readonly "Garbage Collection Confirmation": { + readonly def: "Garbage Collection Confirmation"; + readonly ja: "Garbage Collection の確認"; + readonly ko: "Garbage Collection 확인"; + readonly ru: "Подтверждение Garbage Collection"; + readonly zh: "垃圾回收确认"; + readonly "zh-tw": "垃圾回收確認"; + }; + readonly "Garbage Collection V3 (Beta)": { + readonly def: "Garbage Collection V3 (Beta)"; + readonly es: "Recolección de basura V3 (Beta)"; + readonly ja: "ガーベジコレクション V3 (Beta)"; + readonly ko: "가비지 컬렉션 V3 (Beta)"; + readonly ru: "Сборка мусора V3 (Beta)"; + readonly zh: "垃圾回收 V3(Beta)"; + readonly "zh-tw": "垃圾回收 V3(Beta)"; + }; + readonly "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": { + readonly def: "Garbage Collection: Found ${unusedChunks} unused chunks to delete."; + readonly ja: "Garbage Collection: 削除対象の未使用チャンクが ${unusedChunks} 件見つかりました。"; + readonly ko: "Garbage Collection: 삭제할 미사용 청크 ${unusedChunks}개를 찾았습니다."; + readonly ru: "Garbage Collection: найдено ${unusedChunks} неиспользуемых чанков для удаления."; + readonly zh: "垃圾回收:发现 ${unusedChunks} 个未使用的 chunks 待删除。"; + readonly "zh-tw": "垃圾回收:找到 ${unusedChunks} 個未使用的 chunks 可刪除。"; + }; + readonly "Garbage Collection: Scanned ${scanned} / ~${docCount}": { + readonly def: "Garbage Collection: Scanned ${scanned} / ~${docCount}"; + readonly ja: "Garbage Collection: ${scanned} / ~${docCount} をスキャン済み"; + readonly ko: "Garbage Collection: ${scanned} / ~${docCount} 스캔됨"; + readonly ru: "Garbage Collection: просканировано ${scanned} / ~${docCount}"; + readonly zh: "垃圾回收:已扫描 ${scanned} / ~${docCount}"; + readonly "zh-tw": "垃圾回收:已掃描 ${scanned} / ~${docCount}"; + }; + readonly "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": { + readonly def: "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}"; + readonly ja: "Garbage Collection: スキャン完了。総チャンク数: ${totalChunks}、使用中チャンク数: ${usedChunks}"; + readonly ko: "Garbage Collection: 스캔 완료. 전체 청크 수: ${totalChunks}, 사용 중인 청크 수: ${usedChunks}"; + readonly ru: "Garbage Collection: сканирование завершено. Всего чанков: ${totalChunks}, используемых чанков: ${usedChunks}"; + readonly zh: "垃圾回收:扫描完成。总 chunks:${totalChunks},已使用 chunks:${usedChunks}"; + readonly "zh-tw": "垃圾回收:掃描完成。總 chunks:${totalChunks},已使用 chunks:${usedChunks}"; + }; + readonly "Handle files as Case-Sensitive": { + readonly def: "Handle files as Case-Sensitive"; + readonly es: "Manejar archivos como sensibles a mayúsculas"; + readonly fr: "Gérer les fichiers en respectant la casse"; + readonly he: "טפל בקבצים כתלויי רישיות"; + readonly ja: "ファイルの大文字・小文字を区別する"; + readonly ko: "파일을 대소문자 구분으로 처리"; + readonly ru: "Обрабатывать файлы с учётом регистра"; + readonly zh: "将文件视为区分大小写"; + readonly "zh-tw": "將檔案視為區分大小寫"; + }; + readonly "Hidden Files": { + readonly def: "Hidden Files"; + readonly es: "Archivos ocultos"; + readonly ja: "隠しファイル"; + readonly ko: "숨김 파일"; + readonly ru: "Скрытые файлы"; + readonly zh: "隐藏文件"; + readonly "zh-tw": "隱藏檔案"; + }; + readonly "Hide completely": { + readonly def: "Hide completely"; + readonly zh: "完全隐藏"; + readonly "zh-tw": "完全隱藏"; + }; + readonly "Highlight diff": { + readonly def: "Highlight diff"; + readonly "zh-tw": "醒目顯示差異"; + }; + readonly "How to display network errors when the sync server is unreachable.": { + readonly def: "How to display network errors when the sync server is unreachable."; + readonly es: "Cómo mostrar los errores de red cuando el servidor de sincronización no está disponible."; + readonly ja: "同期サーバーに到達できない場合のネットワークエラーの表示方法を設定します。"; + readonly ko: "동기화 서버에 연결할 수 없을 때 네트워크 오류를 어떻게 표시할지 설정합니다."; + readonly ru: "Определяет, как отображать сетевые ошибки, если сервер синхронизации недоступен."; + readonly zh: "当同步服务器不可达时,如何显示网络错误。"; + readonly "zh-tw": "當同步伺服器無法連線時,如何顯示網路錯誤。"; + }; + readonly "How would you like to configure the connection to your server?": { + readonly def: "How would you like to configure the connection to your server?"; + readonly es: "¿Cómo desea configurar la conexión con su servidor?"; + readonly ja: "サーバー接続をどのように設定しますか?"; + readonly ko: "서버 연결을 어떻게 구성하시겠습니까?"; + readonly ru: "Как вы хотите настроить подключение к серверу?"; + readonly zh: "你希望如何配置与服务器的连接?"; + readonly "zh-tw": "你希望如何設定與伺服器的連線?"; + }; + readonly "I am adding a device to an existing synchronisation setup": { + readonly def: "I am adding a device to an existing synchronisation setup"; + readonly es: "Estoy agregando un dispositivo a una configuración de sincronización existente"; + readonly ja: "既存の同期構成に端末を追加します"; + readonly ko: "기존 동기화 구성에 장치를 추가합니다"; + readonly ru: "Я добавляю устройство к существующей настройке синхронизации"; + readonly zh: "我要将设备加入现有同步配置"; + readonly "zh-tw": "我要將裝置加入既有同步設定"; + }; + readonly "I am setting this up for the first time": { + readonly def: "I am setting this up for the first time"; + readonly es: "Estoy configurando esto por primera vez"; + readonly ja: "はじめて設定します"; + readonly ko: "처음으로 설정합니다"; + readonly ru: "Я настраиваю это впервые"; + readonly zh: "我是第一次进行设置"; + readonly "zh-tw": "我是第一次進行設定"; + }; + readonly "I know my server details, let me enter them": { + readonly def: "I know my server details, let me enter them"; + readonly es: "Conozco los datos de mi servidor; permítame introducirlos"; + readonly ja: "サーバー情報を把握しているので、自分で入力します"; + readonly ko: "서버 정보를 알고 있으니 직접 입력하겠습니다"; + readonly ru: "Я знаю параметры сервера, позвольте ввести их вручную"; + readonly zh: "我知道服务器详情,让我手动输入"; + readonly "zh-tw": "我知道伺服器資訊,讓我手動輸入"; + }; + readonly "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": { + readonly def: "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour)."; + readonly es: "Si se desactiva, chunks se dividen en hilo UI (comportamiento anterior)"; + readonly fr: "Si désactivé, les fragments seront découpés sur le thread UI (comportement précédent)."; + readonly he: "אם מכובה, נתחים יפוצלו בשרשור ממשק המשתמש (התנהגות קודמת)."; + readonly ja: "無効(トグル)にすると、チャンクはUIスレッドで分割されます(以前の動作)。"; + readonly ko: "비활성화(토글)되면 청크는 UI 스레드에서 분할됩니다 (이전 동작)."; + readonly ru: "Если отключено, чанки будут разделяться в основном потоке."; + readonly zh: "如果禁用(切换),chunks 将在 UI 线程上分割(以前的行为)"; + readonly "zh-tw": "若停用(關閉)此選項,chunks 會在 UI 執行緒上分割(舊有行為)。"; + }; + readonly "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": { + readonly def: "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions."; + readonly es: "Habilita sincronización eficiente por archivo. Requiere migración y actualizar todos dispositivos a v0.23.18. Pierde compatibilidad con versiones antiguas"; + readonly fr: "Si activée, la synchronisation de personnalisation efficace par fichier sera utilisée. Une petite migration est nécessaire lors de l'activation. Tous les appareils doivent être à jour en v0.23.18. Une fois cette option activée, la compatibilité avec les anciennes versions est perdue."; + readonly he: "אם מופעל, ייעשה שימוש בסנכרון התאמה אישית יעיל לפי קובץ. נדרשת הגירה קטנה בעת ההפעלה. כל המכשירים צריכים להיות מעודכנים לגרסה 0.23.18. לאחר ההפעלה, התאימות לגרסאות ישנות תיפגע."; + readonly ja: "有効にすると、ファイルごとの効率的なカスタマイズ同期が使用されます。有効化時に小規模な移行が必要です。また、すべてのデバイスをv0.23.18にアップデートする必要があります。一度有効にすると、古いバージョンとの互換性がなくなります。"; + readonly ko: "활성화하면 파일별 효율적인 사용자 설정 동기화가 사용됩니다. 이를 활성화할 때 소규모 데이터 구조 전환이 필요합니다. 모든 기기를 v0.23.18로 업데이트해야 합니다. 이를 활성화하면 이전 버전과의 호환성이 사라집니다."; + readonly ru: "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions."; + readonly zh: "如果启用,将使用基于文件的、高效的自定义同步。启用此功能需要进行一次小的迁移。所有设备都应更新到 v0.23.18。一旦启用此功能,我们将失去与旧版本的兼容性"; + readonly "zh-tw": "啟用後會使用以每個檔案為單位的高效率自訂同步。啟用時需要進行一次小型遷移,且所有裝置都應升級到 v0.23.18。啟用後將不再相容舊版本。"; + }; + readonly "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": { + readonly def: "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker."; + readonly es: "Divide chunks en máximo 100 ítems. Menos eficiente en deduplicación"; + readonly fr: "Si activée, les fragments seront découpés en 100 éléments au maximum. Cependant, la déduplication est légèrement moins efficace."; + readonly he: "אם מופעל, נתחים יפוצלו לא ליותר מ-100 פריטים. עם זאת, ביטול כפילויות יהיה חלש מעט יותר."; + readonly ja: "有効にすると、チャンクは最大100項目に分割されます。ただし、重複除去の精度は落ちます。"; + readonly ko: "활성화하면 청크는 최대 100개 항목으로 분할됩니다. 하지만 중복 제거 기능이 약간 약해집니다."; + readonly ru: "Если включено, чанки будут разделены не более чем на 100 элементов."; + readonly zh: "如果启用,数据块将被分割成不超过 100 项。但是,去重效果会稍弱"; + readonly "zh-tw": "啟用後,chunks 最多會分成 100 個項目,但去重效果會稍微變弱。"; + }; + readonly "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": { + readonly def: "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised."; + readonly es: "Chunks nuevos se mantienen temporalmente en el documento hasta estabilizarse"; + readonly fr: "Si activée, les fragments nouvellement créés sont temporairement conservés dans le document et promus en fragments indépendants une fois stabilisés."; + readonly he: "אם מופעל, נתחים שנוצרו לאחרונה נשמרים זמנית בתוך המסמך, ומוסמכים לנתחים עצמאיים לאחר יציבות."; + readonly ja: "有効にすると、新しく作成されたチャンクはドキュメント内に一時的に保持され、安定したら独立したチャンクになります。"; + readonly ko: "활성화하면 새로 생성된 변경 기록(청크)은 문서 안에 임시로 보관되며, 일정 조건을 만족하면 자동으로 문서 밖으로 분리되어 저장됩니다."; + readonly ru: "Если включено, вновь созданные чанки временно хранятся в документе."; + readonly zh: "如果启用,新创建的数据块将暂时保留在文档中,并在稳定后成为独立数据块"; + readonly "zh-tw": "啟用後,新建立的 chunks 會暫時保留在文件中,待穩定後再獨立出去。"; + }; + readonly "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": { + readonly def: "If enabled, the ⛔ icon will be shown inside the status instead of the file warnings banner. No details will be shown."; + readonly es: "Si se activa, se mostrará el icono ⛔ en el estado en lugar del banner de advertencia de archivos. No se mostrarán detalles."; + readonly fr: "Si activée, l'icône ⛔ s'affichera dans le statut à la place de la bannière d'avertissements de fichiers. Aucun détail ne sera affiché."; + readonly he: "אם מופעל, אייקון ⛔ יוצג בסטטוס במקום פס האזהרות. לא יוצגו פרטים."; + readonly ja: "有効にすると、ファイル警告バナーの代わりにステータス内へ ⛔ アイコンのみを表示します。詳細は表示されません。"; + readonly ko: "활성화하면 파일 경고 배너 대신 상태 영역에 ⛔ 아이콘만 표시됩니다. 자세한 내용은 표시되지 않습니다."; + readonly ru: "Если включено, значок будет показан внутри статуса."; + readonly zh: "如果启用,状态栏内将显示 ⛔ 图标,而非文件警告横幅,不会显示任何详细信息。"; + readonly "zh-tw": "啟用後,將在狀態列中顯示 ⛔ 圖示,而不是檔案警告橫幅,且不會顯示詳細資訊。"; + }; + readonly "If enabled, the file under 1kb will be processed in the UI thread.": { + readonly def: "If enabled, the file under 1kb will be processed in the UI thread."; + readonly es: "Archivos <1kb se procesan en hilo UI"; + readonly fr: "Si activée, les fichiers de moins de 1 Ko seront traités sur le thread UI."; + readonly he: "אם מופעל, קבצים קטנים מ-1KB יעובדו בשרשור ממשק המשתמש."; + readonly ja: "有効にすると、1kb未満のファイルはUIスレッドで処理されます。"; + readonly ko: "활성화하면 1kb 미만의 파일은 UI 스레드에서 처리됩니다."; + readonly ru: "Если включено, файлы меньше 1КБ будут обрабатываться в основном потоке."; + readonly zh: "如果启用,小于 1kb 的文件将在 UI 线程中处理"; + readonly "zh-tw": "啟用後,小於 1KB 的檔案會在 UI 執行緒中處理。"; + }; + readonly "If enabled, the notification of hidden files change will be suppressed.": { + readonly def: "If enabled, the notification of hidden files change will be suppressed."; + readonly es: "Si se habilita, se suprimirá la notificación de cambios en archivos ocultos."; + readonly fr: "Si activée, les notifications de modifications des fichiers cachés seront supprimées."; + readonly he: "אם מופעל, התראות על שינוי בקבצים נסתרים יודחקו."; + readonly ja: "有効にすると、隠しファイルの変更通知が抑制されます。"; + readonly ko: "활성화하면 숨겨진 파일 변경 알림이 억제됩니다."; + readonly ru: "Если включено, уведомление об изменении скрытых файлов будет подавлено."; + readonly zh: "如果启用,将不再通知隐藏文件被更改"; + readonly "zh-tw": "啟用後,將不再通知隱藏檔案變更。"; + }; + readonly "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": { + readonly def: "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)"; + readonly es: "Si se habilita, todos los chunks se almacenan con la revisión hecha desde su contenido. (comportamiento anterior)"; + readonly fr: "Si activée, tous les fragments seront stockés avec la révision issue de leur contenu. (Comportement précédent)"; + readonly he: "אם מופעל, כל הנתחים יישמרו עם גרסה המבוססת על תוכנם. (התנהגות קודמת)"; + readonly ja: "有効にすると、すべてのチャンクはコンテンツから作成されたリビジョンと共に保存されます(以前の動作)。"; + readonly ko: "이 옵션이 활성화되면 모든 청크는 콘텐츠에서 생성된 리비전과 함께 저장됩니다. (이전 동작)"; + readonly ru: "Если включено, все чанки будут храниться с ревизией из содержимого."; + readonly zh: "如果启用,所有 chunks 将使用根据其内容生成的修订版本存储(以前的行为)"; + readonly "zh-tw": "啟用後,所有 chunks 都會以其內容產生的修訂版本儲存(舊有行為)。"; + }; + readonly "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": { + readonly def: "If this enabled, All files are handled as case-Sensitive (Previous behaviour)."; + readonly es: "Si se habilita, todos los archivos se manejan como sensibles a mayúsculas (comportamiento anterior)"; + readonly fr: "Si activée, tous les fichiers sont gérés en respectant la casse (comportement précédent)."; + readonly he: "אם מופעל, כל הקבצים מטופלים כתלויי רישיות (התנהגות קודמת)."; + readonly ja: "有効にすると、すべてのファイルは大文字小文字を区別して処理されます(以前の動作)。"; + readonly ko: "이 옵션이 활성화되면 모든 파일이 대소문자를 구분하여 처리됩니다 (이전 동작)."; + readonly ru: "Если включено, все файлы обрабатываются с учётом регистра."; + readonly zh: "如果启用,所有文件都将视为区分大小写(以前的行为)"; + readonly "zh-tw": "啟用後,所有檔案都會以區分大小寫方式處理(舊有行為)。"; + }; + readonly "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": { + readonly def: "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature."; + readonly es: "Divide chunks en segmentos semánticos. No todos los sistemas lo soportan"; + readonly fr: "Si activée, les fragments seront découpés en segments sémantiquement signifiants. Toutes les plateformes ne prennent pas en charge cette fonctionnalité."; + readonly he: "אם מופעל, נתחים יפוצלו לחלקים עם משמעות סמנטית. לא כל הפלטפורמות תומכות בתכונה זו."; + readonly ja: "有効にすると、チャンクは意味的に有意なセグメントに分割されます。すべてのプラットフォームがこの機能をサポートしているわけではありません。"; + readonly ko: "이 옵션을 활성화하면 청크가 문단이나 의미 단위로 나뉘어 저장됩니다. 단, 이 기능은 일부 플랫폼에서는 지원되지 않을 수 있습니다."; + readonly ru: "Если включено, чанки будут разделены на семантически значимые сегменты."; + readonly zh: "如果启用此功能,数据块将被分割成具有语义意义的段落。并非所有平台都支持此功能"; + readonly "zh-tw": "啟用後,chunks 會依語意切分成有意義的區段,並非所有平台都支援此功能。"; + }; + readonly "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": { + readonly def: "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files."; + readonly es: "Saltar cambios en archivos locales que coincidan con ignore files. Cambios remotos usan ignore files locales"; + readonly fr: "Si défini, les modifications des fichiers locaux correspondant aux fichiers d'exclusion seront ignorées. Les changements distants sont déterminés à l'aide des fichiers d'exclusion locaux."; + readonly he: "אם מוגדר, שינויים בקבצים מקומיים התואמים לקבצי ההתעלמות יידלגו. שינויים מרוחקים נקבעים לפי קבצי ההתעלמות המקומיים."; + readonly ja: "これを設定すると、除外ファイルに一致するローカルファイルの変更はスキップされます。リモートの変更はローカルの無視ファイルを使用して判定されます。"; + readonly ko: "이 옵션을 활성화하면, 제외 규칙 파일에 일치하는 로컬 파일의 변경 사항은 건너뜁니다. 원격 변경 여부 또한 로컬의 제외 규칙 파일에 따라 판단됩니다."; + readonly ru: "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files."; + readonly zh: "如果设置了此项,与忽略文件匹配的本地文件的更改将被跳过。远程更改使用本地忽略文件确定"; + }; + readonly "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": { + readonly def: "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage."; + readonly es: "Mantiene conexión 60s. Si no hay cambios, reinicia socket. Útil con proxies limitantes"; + readonly fr: "Si cette option est activée, PouchDB maintiendra la connexion ouverte pendant 60 secondes, et si aucun changement n'arrive durant cette période, fermera et rouvrira la socket au lieu de la garder ouverte indéfiniment. Utile lorsqu'un proxy limite la durée des requêtes, mais peut augmenter l'utilisation des ressources."; + readonly he: "אם אפשרות זו מופעלת, PouchDB ישמור את החיבור פתוח ל-60 שניות, ואם אין שינוי בפרק זמן זה, יסגור ויפתח מחדש את השקע, במקום להחזיק אותו פתוח ללא הגבלה. שימושי כשפרוקסי מגביל משך בקשות, אך עשוי להגביר שימוש במשאבים."; + readonly ja: "このオプションを有効にすると、PouchDBは接続を60秒間保持し、その間に通信がない場合、一度接続を閉じて再接続します。接続を無期限に保持する代わりにこの動作を行います。プロキシ(Cloudflareなど)がリクエストの持続時間を制限している場合に有用ですが、リソース使用量が増加する可能性があります。"; + readonly ko: "이 옵션이 활성화되면 PouchDB는 연결을 더이상 무한히 열어두지 않고 60초 동안 유지합니다. 그 시간 내에 변경 사항이 없으면 소켓을 닫고 다시 엽니다. 프록시가 요청 지속 시간을 제한할 때 유용하지만 리소스 사용량이 증가할 수 있습니다."; + readonly ru: "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage."; + readonly zh: "如果启用此选项,PouchDB 将保持连接打开 60 秒,如果在此时间内没有更改到达,则关闭并重新打开套接字,而不是无限期保持打开。当代理限制请求持续时间时有用,但可能会增加资源使用ß"; + }; + readonly "If you reached the payload size limit when using IBM Cloudant, please decrease batch size and batch limit to a lower value.": { + readonly def: "If you reached the payload size limit when using IBM Cloudant, please decrease batch size and batch limit to a lower value."; + readonly "zh-tw": "如果你在使用 IBM Cloudant 時遇到負載大小上限,請調低批次大小與批次上限。"; + }; + readonly "Ignore and Proceed": { + readonly def: "Ignore and Proceed"; + readonly ja: "無視して続行"; + readonly ko: "무시하고 계속"; + readonly ru: "Игнорировать и продолжить"; + readonly zh: "忽略并继续"; + readonly "zh-tw": "忽略並繼續"; + }; + readonly "Ignore files": { + readonly def: "Ignore files"; + readonly es: "Archivos a ignorar"; + readonly fr: "Fichiers d'exclusion"; + readonly he: "קבצי התעלמות"; + readonly ja: "除外ファイル"; + readonly ko: "제외 규칙 파일"; + readonly ru: "Файлы для игнорирования"; + readonly zh: "忽略文件"; + }; + readonly "Ignore patterns": { + readonly def: "Ignore patterns"; + readonly es: "Patrones de exclusión"; + readonly ja: "除外パターン"; + readonly ko: "무시 패턴"; + readonly ru: "Шаблоны исключения"; + readonly zh: "忽略模式"; + readonly "zh-tw": "忽略模式"; + }; + readonly "Import connection": { + readonly def: "Import connection"; + readonly es: "Importar conexión"; + readonly ja: "接続をインポート"; + readonly ko: "연결 가져오기"; + readonly ru: "Импортировать подключение"; + readonly zh: "导入连接"; + readonly "zh-tw": "匯入連線"; + }; + readonly "Incubate Chunks in Document": { + readonly def: "Incubate Chunks in Document"; + readonly es: "Incubar chunks en documento"; + readonly fr: "Incuber les fragments dans le document"; + readonly he: "בשל נתחים בתוך המסמך"; + readonly ja: "ドキュメント内でチャンクを一時保管する"; + readonly ko: "문서 내 변경 기록 임시 보관"; + readonly ru: "Инкубировать чанки в документе"; + readonly zh: "在文档中孵化块"; + }; + readonly "Initialise all journal history, On the next sync, every item will be received and sent.": { + readonly def: "Initialise all journal history, On the next sync, every item will be received and sent."; + readonly es: "Restablece todo el historial del diario. En la próxima sincronización se recibirán y enviarán todos los elementos."; + readonly ja: "すべてのジャーナル履歴を初期化します。次回の同期時に、すべての項目が再受信・再送信されます。"; + readonly ko: "모든 저널 기록을 초기화합니다. 다음 동기화 때 모든 항목을 다시 받고 다시 보냅니다."; + readonly ru: "Инициализирует всю историю журнала. При следующей синхронизации каждый элемент будет заново получен и отправлен."; + readonly zh: "初始化所有日志历史。下次同步时,所有项目都会重新接收并发送。"; + readonly "zh-tw": "初始化所有日誌歷史。下次同步時,每個項目都會重新接收與傳送。"; + }; + readonly "Initialise journal received history. On the next sync, every item except this device sent will be downloaded again.": { + readonly def: "Initialise journal received history. On the next sync, every item except this device sent will be downloaded again."; + readonly "zh-tw": "初始化接收日誌歷程。下次同步時,除了此裝置已送出的項目外,其他項目都會再次下載。"; + }; + readonly "Initialise journal sent history. On the next sync, every item except this device received will be sent again.": { + readonly def: "Initialise journal sent history. On the next sync, every item except this device received will be sent again."; + readonly "zh-tw": "初始化傳送日誌歷程。下次同步時,除了此裝置已接收的項目外,其他項目都會再次傳送。"; + }; + readonly "Interval (sec)": { + readonly def: "Interval (sec)"; + readonly es: "Intervalo (segundos)"; + readonly fr: "Intervalle (sec)"; + readonly he: "מרווח (שניות)"; + readonly ja: "秒"; + readonly ko: "간격 (초)"; + readonly ru: "Интервал (сек)"; + readonly zh: "间隔(秒)"; + }; + readonly "K.exp": { + readonly def: "Experimental"; + readonly fr: "Expérimental"; + readonly he: "ניסיוני"; + readonly ja: "試験機能"; + readonly ko: "실험 기능"; + readonly ru: "Экспериментальная"; + readonly zh: "实验性"; + }; + readonly "K.long_p2p_sync": { + readonly def: "Peer-to-Peer Sync"; + readonly fr: "Synchronisation pair-à-pair"; + readonly he: "%{title_p2p_sync}"; + readonly ja: "Peer-to-Peer Sync (試験機能)"; + readonly ko: "피어 투 피어(P2P) 동기화 (실험 기능)"; + readonly ru: "title_p2p_sync"; + readonly zh: "Peer-to-Peer同步 (实验性)"; + }; + readonly "K.P2P": { + readonly def: "Peer-to-Peer"; + readonly fr: "Pair-à-Pair"; + readonly he: "%{Peer}-ל-%{Peer}"; + readonly ja: "Peer-to-Peer"; + readonly ko: "피어-to-피어"; + readonly ru: "Peer-к-Peer"; + readonly zh: "Peer-to-Peer"; + }; + readonly "K.Peer": { + readonly def: "Peer"; + readonly fr: "Pair"; + readonly he: "עמית"; + readonly ja: "Peer"; + readonly ko: "피어"; + readonly ru: "Устройство"; + readonly zh: "Peer"; + }; + readonly "K.ScanCustomization": { + readonly def: "Scan customization"; + readonly fr: "Analyser la personnalisation"; + readonly he: "סרוק התאמה אישית"; + readonly ja: "Scan customization"; + readonly ko: "사용자 설정 검색"; + readonly ru: "Scan customization"; + readonly zh: "扫描自定义"; + }; + readonly "K.short_p2p_sync": { + readonly def: "P2P Sync"; + readonly fr: "Sync P2P"; + readonly he: "סנכרון P2P"; + readonly ja: "P2P Sync (試験機能)"; + readonly ko: "P2P 동기화 (실험 기능)"; + readonly ru: "P2P Синхр."; + readonly zh: "P2P同步(实验性)"; + }; + readonly "K.title_p2p_sync": { + readonly def: "Peer-to-Peer Sync"; + readonly fr: "Synchronisation pair-à-pair"; + readonly he: "סנכרון עמית-לעמית"; + readonly ja: "Peer-to-Peer Sync"; + readonly ko: "피어 투 피어(P2P) 동기화"; + readonly ru: "Синхронизация между устройствами"; + readonly zh: "Peer-to-Peer同步"; + }; + readonly "Keep empty folder": { + readonly def: "Keep empty folder"; + readonly es: "Mantener carpetas vacías"; + readonly fr: "Conserver les dossiers vides"; + readonly he: "שמור תיקייה ריקה"; + readonly ja: "空フォルダの維持"; + readonly ko: "빈 폴더 유지"; + readonly ru: "Сохранять пустые папки"; + readonly zh: "保留空文件夹"; + }; + readonly lang_def: { + readonly def: "Default"; + readonly fr: "Par défaut"; + readonly he: "ברירת מחדל"; + readonly ja: "Default"; + readonly ko: "Default"; + readonly ru: "По умолчанию"; + readonly zh: "Default"; + }; + readonly "lang-de": { + readonly def: "Deutsche"; + readonly es: "Alemán"; + readonly fr: "Deutsche"; + readonly he: "Deutsche"; + readonly ja: "Deutsche"; + readonly ko: "Deutsche"; + readonly ru: "Deutsch"; + readonly zh: "Deutsche"; + }; + readonly "lang-def": { + readonly def: "Default"; + readonly fr: "Par défaut"; + readonly he: "%{lang_def}"; + readonly ja: "Default"; + readonly ko: "Default"; + readonly ru: "lang_def"; + readonly zh: "Default"; + }; + readonly "lang-es": { + readonly def: "Español"; + readonly es: "Español"; + readonly fr: "Español"; + readonly he: "Español"; + readonly ja: "Español"; + readonly ko: "Español"; + readonly ru: "Español"; + readonly zh: "Español"; + }; + readonly "lang-fr": { + readonly def: "Français"; + readonly es: "Français"; + readonly fr: "Français"; + readonly he: "Français"; + readonly ja: "Français"; + readonly ko: "Français"; + readonly ru: "Français"; + readonly zh: "Français"; + }; + readonly "lang-he": { + readonly def: "Hebrew"; + readonly he: "עברית"; + }; + readonly "lang-ja": { + readonly def: "日本語"; + readonly es: "Japonés"; + readonly fr: "日本語"; + readonly he: "日本語"; + readonly ja: "日本語"; + readonly ko: "日本語"; + readonly ru: "日本語"; + readonly zh: "日本語"; + }; + readonly "lang-ko": { + readonly def: "한국어"; + readonly fr: "한국어"; + readonly he: "한국어"; + readonly ja: "한국어"; + readonly ko: "한국어"; + readonly ru: "한국어"; + readonly zh: "한국어"; + }; + readonly "lang-ru": { + readonly def: "Русский"; + readonly es: "Ruso"; + readonly fr: "Русский"; + readonly he: "Русский"; + readonly ja: "Русский"; + readonly ko: "Русский"; + readonly ru: "Русский"; + readonly zh: "Русский"; + }; + readonly "lang-zh": { + readonly def: "简体中文"; + readonly es: "Chino simplificado"; + readonly fr: "简体中文"; + readonly he: "简体中文"; + readonly ja: "简体中文"; + readonly ko: "简体中文"; + readonly ru: "简体中文"; + readonly zh: "简体中文"; + }; + readonly "lang-zh-tw": { + readonly def: "繁體中文"; + readonly es: "Chino tradicional"; + readonly fr: "繁體中文"; + readonly he: "繁體中文"; + readonly ja: "繁體中文"; + readonly ko: "繁體中文"; + readonly ru: "繁體中文"; + readonly zh: "繁體中文"; + }; + readonly Later: { + readonly def: "Later"; + readonly es: "Más tarde"; + readonly ja: "後で"; + readonly ko: "나중에"; + readonly ru: "Позже"; + readonly zh: "稍后"; + readonly "zh-tw": "稍後"; + }; + readonly "Limit: {datetime} ({timestamp})": { + readonly def: "Limit: {datetime} ({timestamp})"; + readonly es: "Límite: {datetime} ({timestamp})"; + readonly ja: "制限: {datetime} ({timestamp})"; + readonly ko: "제한: {datetime} ({timestamp})"; + readonly ru: "Лимит: {datetime} ({timestamp})"; + readonly zh: "限制:{datetime}({timestamp})"; + readonly "zh-tw": "限制:{datetime}({timestamp})"; + }; + readonly "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": { + readonly def: "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured."; + readonly es: "LiveSync no puede manejar múltiples bóvedas con mismo nombre sin prefijo. Se configura automáticamente"; + readonly fr: "LiveSync ne peut pas gérer plusieurs coffres portant le même nom sans préfixe distinct. Ceci devrait être configuré automatiquement."; + readonly he: "LiveSync אינו יכול לטפל במספר כספות עם אותו שם ללא קידומת שונה. הדבר אמור להיות מוגדר אוטומטית."; + readonly ja: "LiveSyncは、接頭辞(プレフィックス)のない同名の保管庫(Vault)を扱うことができません。これは自動的に設定されます。"; + readonly ko: "LiveSync는 서로 다른 접두사 없이 동일한 이름을 가진 여러 볼트를 처리할 수 없습니다. 이는 자동으로 구성되어야 합니다."; + readonly ru: "LiveSync не может обработать несколько хранилищ с одинаковым именем без разных префиксов."; + readonly zh: "LiveSync 无法处理具有相同名称但没有不同前缀的多个库。这应该自动配置"; + }; + readonly "liveSyncReplicator.beforeLiveSync": { + readonly def: "Before LiveSync, start OneShot once..."; + readonly es: "Antes de LiveSync, inicia OneShot..."; + readonly fr: "Avant LiveSync, lancement d'un OneShot initial..."; + readonly he: "לפני LiveSync, התחל OneShot פעם אחת..."; + readonly ja: "LiveSyncの前に、まずOneShotを開始します..."; + readonly ko: "LiveSync 전에 OneShot을 먼저 시작합니다..."; + readonly ru: "Перед LiveSync запускаем OneShot..."; + readonly zh: "在LiveSync前,先启动OneShot一次..."; + }; + readonly "liveSyncReplicator.cantReplicateLowerValue": { + readonly def: "We can't replicate more lower value."; + readonly es: "No podemos replicar un valor más bajo."; + readonly fr: "Impossible de répliquer une valeur inférieure."; + readonly he: "לא ניתן לשכפל ערך נמוך יותר."; + readonly ja: "これ以上低い値ではレプリケーション(複製)できません。"; + readonly ko: "더 낮은 값으로 복제할 수 없습니다."; + readonly ru: "Нельзя реплицировать с меньшим значением."; + readonly zh: "我们无法复制更小的值"; + }; + readonly "liveSyncReplicator.checkingLastSyncPoint": { + readonly def: "Looking for the point last synchronized point."; + readonly es: "Buscando el último punto sincronizado."; + readonly fr: "Recherche du dernier point de synchronisation."; + readonly he: "מחפש נקודת הסנכרון האחרונה."; + readonly ja: "最後に同期したポイントを探しています。"; + readonly ko: "마지막으로 동기화된 지점을 찾고 있습니다."; + readonly ru: "Поиск последней точки синхронизации."; + readonly zh: "查找上次同步点"; + }; + readonly "liveSyncReplicator.couldNotConnectTo": { + readonly def: "Could not connect to ${uri} : ${name}\n(${db})"; + readonly es: "No se pudo conectar a ${uri} : ${name} \n(${db})"; + readonly fr: "Connexion impossible à ${uri} : ${name}\n(${db})"; + readonly he: "לא ניתן להתחבר אל ${uri} : ${name}\n(${db})"; + readonly ja: "${uri} : ${name}に接続できませんでした\n(${db})"; + readonly ko: "${uri}에 연결할 수 없습니다: ${name} \n(${db})"; + readonly ru: "Не удалось подключиться к uri : name\n(db)"; + readonly zh: "无法连接到 ${uri} : ${name}\n(${db})"; + }; + readonly "liveSyncReplicator.couldNotConnectToRemoteDb": { + readonly def: "Could not connect to remote database: ${d}"; + readonly es: "No se pudo conectar a base de datos remota: ${d}"; + readonly fr: "Connexion à la base distante impossible : ${d}"; + readonly he: "לא ניתן להתחבר למסד הנתונים המרוחק: ${d}"; + readonly ja: "リモートデータベースに接続できませんでした: ${d}"; + readonly ko: "원격 데이터베이스에 연결할 수 없습니다: ${d}"; + readonly ru: "Не удалось подключиться к удалённой базе данных: d"; + readonly zh: "无法连接到远程数据库:${d}"; + }; + readonly "liveSyncReplicator.couldNotConnectToServer": { + readonly def: "The connection to the remote has been prevented, or failed."; + readonly es: "No se pudo conectar al servidor."; + readonly fr: "Connexion au serveur impossible."; + readonly he: "לא ניתן להתחבר לשרת."; + readonly ja: "サーバーに接続できませんでした。"; + readonly ko: "서버에 연결할 수 없습니다."; + readonly ru: "Не удалось подключиться к серверу."; + readonly zh: "无法连接到服务器"; + }; + readonly "liveSyncReplicator.couldNotConnectToURI": { + readonly def: "Could not connect to ${uri}:${dbRet}"; + readonly es: "No se pudo conectar a ${uri}:${dbRet}"; + readonly fr: "Connexion impossible à ${uri}:${dbRet}"; + readonly he: "לא ניתן להתחבר אל ${uri}:${dbRet}"; + readonly ja: "${uri}に接続できませんでした: ${dbRet}"; + readonly ko: "${uri}에 연결할 수 없습니다: ${dbRet}"; + readonly ru: "Не удалось подключиться к uri:dbRet"; + readonly zh: "无法连接到 ${uri}:${dbRet}"; + }; + readonly "liveSyncReplicator.couldNotMarkResolveRemoteDb": { + readonly def: "Could not mark resolve remote database."; + readonly es: "No se pudo marcar como resuelta la base de datos remota."; + readonly fr: "Impossible de marquer la résolution de la base distante."; + readonly he: "לא ניתן לסמן פתרון למסד הנתונים המרוחק."; + readonly ja: "リモートデータベースを解決済みとしてマークできませんでした。"; + readonly ko: "원격 데이터베이스를 해결됨으로 표시할 수 없습니다."; + readonly ru: "Не удалось отметить удалённую базу данных как разрешённую."; + readonly zh: "无法标记并解决远程数据库"; + }; + readonly "liveSyncReplicator.liveSyncBegin": { + readonly def: "LiveSync begin..."; + readonly es: "Inicio de LiveSync..."; + readonly fr: "Démarrage de LiveSync..."; + readonly he: "LiveSync מתחיל..."; + readonly ja: "LiveSyncを開始..."; + readonly ko: "LiveSync 시작..."; + readonly ru: "Начало LiveSync..."; + readonly zh: "LiveSync 开始..."; + }; + readonly "liveSyncReplicator.lockRemoteDb": { + readonly def: "Lock remote database to prevent data corruption"; + readonly es: "Bloquear base de datos remota para prevenir corrupción de datos"; + readonly fr: "Verrouillage de la base distante pour éviter la corruption des données"; + readonly he: "נועל מסד נתונים מרוחק למניעת פגיעה בנתונים"; + readonly ja: "データ破損を防ぐためリモートデータベースをロック"; + readonly ko: "데이터 손상을 방지하기 위해 원격 데이터베이스를 잠급니다"; + readonly ru: "Блокировка удалённой базы данных для предотвращения повреждения данных"; + readonly zh: "锁定远程数据库以防止数据损坏"; + }; + readonly "liveSyncReplicator.markDeviceResolved": { + readonly def: "Mark this device as 'resolved'."; + readonly es: "Marcar este dispositivo como 'resuelto'."; + readonly fr: "Marquer cet appareil comme « résolu »."; + readonly he: "סמן מכשיר זה כ'נפתר'."; + readonly ja: "このデバイスを『解決済み』としてマーク。"; + readonly ko: "이 기기를 '해결됨'으로 표시합니다."; + readonly ru: "Отметить это устройство как «разрешённое»."; + readonly zh: "将此设备标记为“已解决”"; + }; + readonly "liveSyncReplicator.mismatchedTweakDetected": { + readonly def: "Some mismatches have been detected in the configuration between devices. Running a manual replication will attempt to resolve this issue."; + }; + readonly "liveSyncReplicator.oneShotSyncBegin": { + readonly def: "OneShot Sync begin... (${syncMode})"; + readonly es: "Inicio de sincronización OneShot... (${syncMode})"; + readonly fr: "Démarrage de la synchronisation OneShot... (${syncMode})"; + readonly he: "סנכרון OneShot מתחיל... (${syncMode})"; + readonly ja: "OneShot同期を開始... (${syncMode})"; + readonly ko: "OneShot 동기화 시작... (${syncMode})"; + readonly ru: "Начало OneShot синхронизации... (syncMode)"; + readonly zh: "OneShot同步开始...(${syncMode})"; + }; + readonly "liveSyncReplicator.remoteDbCorrupted": { + readonly def: "Remote database is newer or corrupted, make sure to latest version of self-hosted-livesync installed"; + readonly es: "La base de datos remota es más nueva o está dañada, asegúrese de tener la última versión de self-hosted-livesync instalada"; + readonly fr: "La base distante est plus récente ou corrompue, assurez-vous d'avoir installé la dernière version de self-hosted-livesync"; + readonly he: "מסד הנתונים המרוחק חדש יותר או פגום, ודא שגרסת self-hosted-livesync המותקנת היא העדכנית ביותר"; + readonly ja: "リモートデータベースが新しいか破損しています。self-hosted-livesyncの最新バージョンがインストールされていることを確認してください"; + readonly ko: "원격 데이터베이스가 더 최신이거나 손상되었습니다. 최신 버전의 self-hosted-livesync가 설치되어 있는지 확인하세요"; + readonly ru: "Удалённая база данных новее или повреждена, убедитесь, что установлена последняя версия self-hosted-livesync"; + readonly zh: "远程数据库较新或已损坏,请确保已安装最新版本的self-hosted-livesync"; + }; + readonly "liveSyncReplicator.remoteDbCreatedOrConnected": { + readonly def: "Remote Database Created or Connected"; + readonly es: "Base de datos remota creada o conectada"; + readonly fr: "Base distante créée ou connectée"; + readonly he: "מסד הנתונים המרוחק נוצר או חובר"; + readonly ja: "リモートデータベースが作成または接続されました"; + readonly ko: "원격 데이터베이스가 생성되거나 연결되었습니다"; + readonly ru: "Удалённая база данных создана или подключена"; + readonly zh: "远程数据库已创建或连接"; + }; + readonly "liveSyncReplicator.remoteDbDestroyed": { + readonly def: "Remote Database Destroyed"; + readonly es: "Base de datos remota destruida"; + readonly fr: "Base distante détruite"; + readonly he: "מסד הנתונים המרוחק נהרס"; + readonly ja: "リモートデータベースが削除されました"; + readonly ko: "원격 데이터베이스가 삭제되었습니다"; + readonly ru: "Удалённая база данных уничтожена"; + readonly zh: "远程数据库已销毁"; + }; + readonly "liveSyncReplicator.remoteDbDestroyError": { + readonly def: "Something happened on Remote Database Destroy:"; + readonly es: "Algo ocurrió al destruir base de datos remota:"; + readonly fr: "Un problème est survenu lors de la destruction de la base distante :"; + readonly he: "אירעה שגיאה בהריסת מסד הנתונים המרוחק:"; + readonly ja: "リモートデータベースの削除中に問題が発生しました:"; + readonly ko: "원격 데이터베이스 삭제 중 오류가 발생했습니다:"; + readonly ru: "Произошла ошибка при уничтожении удалённой базы данных:"; + readonly zh: "远程数据库销毁时发生错误:"; + }; + readonly "liveSyncReplicator.remoteDbMarkedResolved": { + readonly def: "Remote database has been marked resolved."; + readonly es: "Base de datos remota marcada como resuelta."; + readonly fr: "La base distante a été marquée comme résolue."; + readonly he: "מסד הנתונים המרוחק סומן כנפתר."; + readonly ja: "リモートデータベースが解決済みとしてマークされました。"; + readonly ko: "원격 데이터베이스가 해결됨으로 표시되었습니다."; + readonly ru: "Удалённая база данных отмечена как разрешённая."; + readonly zh: "远程数据库已标记为已解决"; + }; + readonly "liveSyncReplicator.replicationClosed": { + readonly def: "Replication closed"; + readonly es: "Replicación cerrada"; + readonly fr: "Réplication fermée"; + readonly he: "השכפול נסגר"; + readonly ja: "レプリケーション(複製)が終了しました"; + readonly ko: "복제가 종료되었습니다"; + readonly ru: "Репликация закрыта"; + readonly zh: "同步已关闭"; + }; + readonly "liveSyncReplicator.replicationInProgress": { + readonly def: "Replication is already in progress"; + readonly es: "Replicación en curso"; + readonly fr: "Une réplication est déjà en cours"; + readonly he: "שכפול כבר מתבצע"; + readonly ja: "レプリケーション(複製)は既に進行中です"; + readonly ko: "복제가 이미 진행 중입니다"; + readonly ru: "Репликация уже выполняется"; + readonly zh: "同步正在进行中"; + }; + readonly "liveSyncReplicator.retryLowerBatchSize": { + readonly def: "Retry with lower batch size:${batch_size}/${batches_limit}"; + readonly es: "Reintentar con tamaño de lote más bajo:${batch_size}/${batches_limit}"; + readonly fr: "Nouvelle tentative avec une taille de lot réduite :${batch_size}/${batches_limit}"; + readonly he: "מנסה שוב עם גודל אצווה קטן יותר:${batch_size}/${batches_limit}"; + readonly ja: "より小さいバッチサイズで再試行: ${batch_size}/${batches_limit}"; + readonly ko: "더 낮은 일괄 크기로 재시도: ${batch_size}/${batches_limit}"; + readonly ru: "Повтор с меньшим размером пакета: batch_size/batches_limit"; + readonly zh: "使用更小的批量大小重试:${batch_size}/${batches_limit}"; + }; + readonly "liveSyncReplicator.unlockRemoteDb": { + readonly def: "Unlock remote database to prevent data corruption"; + readonly es: "Desbloquear base de datos remota para prevenir corrupción de datos"; + readonly fr: "Déverrouillage de la base distante pour éviter la corruption des données"; + readonly he: "מבטל נעילת מסד הנתונים המרוחק למניעת פגיעה בנתונים"; + readonly ja: "データ破損を防ぐためリモートデータベースをアンロック"; + readonly ko: "데이터 손상을 방지하기 위해 원격 데이터베이스를 잠금 해제합니다"; + readonly ru: "Разблокировка удалённой базы данных для предотвращения повреждения данных"; + readonly zh: "解锁远程数据库以防止数据损坏"; + }; + readonly "liveSyncSetting.errorNoSuchSettingItem": { + readonly def: "No such setting item: ${key}"; + readonly es: "No existe el ajuste: ${key}"; + readonly fr: "Élément de paramètre inexistant : ${key}"; + readonly he: "פריט הגדרה לא קיים: ${key}"; + readonly ja: "その設定項目は存在しません: ${key}"; + readonly ko: "해당 설정 항목이 없습니다: ${key}"; + readonly ru: "Такого параметра настройки не существует: key"; + readonly zh: "没有此设置项:${key}"; + }; + readonly "liveSyncSetting.originalValue": { + readonly def: "Original: ${value}"; + readonly es: "Original: ${value}"; + readonly fr: "Original : ${value}"; + readonly he: "ערך מקורי: ${value}"; + readonly ja: "元の値: ${value}"; + readonly ko: "원본: ${value}"; + readonly ru: "Оригинал: value"; + readonly zh: "原始值:${value}"; + }; + readonly "liveSyncSetting.valueShouldBeInRange": { + readonly def: "The value should ${min} < value < ${max}"; + readonly es: "El valor debe estar entre ${min} y ${max}"; + readonly fr: "La valeur doit être ${min} < valeur < ${max}"; + readonly he: "הערך צריך להיות ${min} < ערך < ${max}"; + readonly ja: "値は ${min} < 値 < ${max} の範囲である必要があります"; + readonly ko: "값은 ${min} < 값 < ${max} 범위에 있어야 합니다"; + readonly ru: "Значение должно быть min < значение < max"; + readonly zh: "值应该在 ${min} < value < ${max} 之间"; + }; + readonly "liveSyncSettings.btnApply": { + readonly def: "Apply"; + readonly es: "Aplicar"; + readonly fr: "Appliquer"; + readonly he: "החל"; + readonly ja: "適用"; + readonly ko: "적용"; + readonly ru: "Применить"; + readonly zh: "应用"; + }; + readonly "Local Database Tweak": { + readonly def: "Local Database Tweak"; + readonly es: "Ajustes de la base de datos local"; + readonly ja: "ローカルデータベースの調整"; + readonly ko: "로컬 데이터베이스 조정"; + readonly ru: "Настройки локальной базы данных"; + }; + readonly Lock: { + readonly def: "Lock"; + readonly es: "Bloquear"; + readonly ja: "ロック"; + readonly ko: "잠금"; + readonly ru: "Заблокировать"; + readonly zh: "锁定"; + readonly "zh-tw": "鎖定"; + }; + readonly "Lock Server": { + readonly def: "Lock Server"; + readonly es: "Bloquear servidor"; + readonly ja: "サーバーをロック"; + readonly ko: "서버 잠금"; + readonly ru: "Заблокировать сервер"; + readonly zh: "锁定服务器"; + readonly "zh-tw": "鎖定伺服器"; + }; + readonly "Lock the remote server to prevent synchronization with other devices.": { + readonly def: "Lock the remote server to prevent synchronization with other devices."; + readonly es: "Bloquea el servidor remoto para impedir la sincronización con otros dispositivos."; + readonly ja: "他のデバイスとの同期を防ぐため、リモートサーバーをロックします。"; + readonly ko: "다른 기기와의 동기화를 방지하기 위해 원격 서버를 잠급니다."; + readonly ru: "Блокирует удалённый сервер, чтобы запретить синхронизацию с другими устройствами."; + readonly zh: "锁定远端服务器,以阻止其他设备继续同步。"; + readonly "zh-tw": "鎖定遠端伺服器,以防止其他裝置進行同步。"; + }; + readonly "logPane.autoScroll": { + readonly def: "Auto scroll"; + readonly es: "Autodesplazamiento"; + readonly fr: "Défilement automatique"; + readonly he: "גלילה אוטומטית"; + readonly ja: "自動スクロール"; + readonly ko: "자동 스크롤"; + readonly ru: "Автопрокрутка"; + readonly zh: "自动滚动"; + }; + readonly "logPane.logWindowOpened": { + readonly def: "Log window opened"; + readonly es: "Ventana de registro abierta"; + readonly fr: "Fenêtre des journaux ouverte"; + readonly he: "חלון יומן נפתח"; + readonly ja: "ログウィンドウが開かれました"; + readonly ko: "로그 창이 열렸습니다"; + readonly ru: "Окно лога открыто"; + readonly zh: "日志窗口已打开"; + }; + readonly "logPane.pause": { + readonly def: "Pause"; + readonly es: "Pausar"; + readonly fr: "Pause"; + readonly he: "השהה"; + readonly ja: "一時停止"; + readonly ko: "일시 중단"; + readonly ru: "Пауза"; + readonly zh: "暂停"; + }; + readonly "logPane.title": { + readonly def: "Self-hosted LiveSync Log"; + readonly es: "Registro de Self-hosted LiveSync"; + readonly fr: "Journaux Self-hosted LiveSync"; + readonly he: "יומן Self-hosted LiveSync"; + readonly ja: "Self-hosted LiveSync ログ"; + readonly ko: "Self-hosted LiveSync 로그"; + readonly ru: "Лог Self-hosted LiveSync"; + readonly zh: "Self-hosted LiveSync 日志"; + }; + readonly "logPane.wrap": { + readonly def: "Wrap"; + readonly es: "Ajustar"; + readonly fr: "Retour à la ligne"; + readonly he: "גלישת שורות"; + readonly ja: "折り返し"; + readonly ko: "줄 바꿈"; + readonly ru: "Перенос"; + readonly zh: "自动换行"; + }; + readonly "Maximum delay for batch database updating": { + readonly def: "Maximum delay for batch database updating"; + readonly es: "Retraso máximo para actualización por lotes"; + readonly fr: "Délai maximum pour la mise à jour groupée de la base"; + readonly he: "עיכוב מקסימלי לעדכון אצווה של מסד נתונים"; + readonly ja: "バッチデータベース更新の最大遅延"; + readonly ko: "일괄 데이터베이스 업데이트 최대 지연"; + readonly ru: "Максимальная задержка пакетного обновления базы данных"; + readonly zh: "批量数据库更新的最大延迟"; + }; + readonly "Maximum file size": { + readonly def: "Maximum file size"; + readonly es: "Tamaño máximo de archivo"; + readonly fr: "Taille maximale de fichier"; + readonly he: "גודל קובץ מקסימלי"; + readonly ja: "最大ファイル容量"; + readonly ko: "최대 파일 크기"; + readonly ru: "Максимальный размер файла"; + readonly zh: "最大文件大小"; + }; + readonly "Maximum Incubating Chunk Size": { + readonly def: "Maximum Incubating Chunk Size"; + readonly es: "Tamaño máximo de chunks incubados"; + readonly fr: "Taille maximale des fragments en incubation"; + readonly he: "גודל מקסימלי לנתח בבישול"; + readonly ja: "保持するチャンクの最大サイズ"; + readonly ko: "임시 보관 변경 기록의 최대 크기"; + readonly ru: "Максимальный размер инкубируемого чанка"; + readonly zh: "最大孵化块大小"; + }; + readonly "Maximum Incubating Chunks": { + readonly def: "Maximum Incubating Chunks"; + readonly es: "Máximo de chunks incubados"; + readonly fr: "Nombre maximum de fragments en incubation"; + readonly he: "מספר מקסימלי של נתחים בבישול"; + readonly ja: "一時保管する最大チャンク数"; + readonly ko: "임시 보관 중인 변경 기록 최대 수"; + readonly ru: "Максимальное количество инкубируемых чанков"; + readonly zh: "最大孵化块数"; + }; + readonly "Maximum Incubation Period": { + readonly def: "Maximum Incubation Period"; + readonly es: "Periodo máximo de incubación"; + readonly fr: "Période maximale d'incubation"; + readonly he: "תקופת בישול מקסימלית"; + readonly ja: "最大保持期限"; + readonly ko: "변경 기록 임시 보관 최대 시간"; + readonly ru: "Максимальный период инкубации"; + readonly zh: "最大孵化期"; + }; + readonly "MB (0 to disable).": { + readonly def: "MB (0 to disable)."; + readonly es: "MB (0 para desactivar)"; + readonly fr: "Mo (0 pour désactiver)."; + readonly he: "MB (0 לביטול)."; + readonly ja: "MB (0で無効化)。"; + readonly ko: "MB (0으로 설정하면 비활성화)."; + readonly ru: "МБ (0 для отключения)."; + readonly zh: "MB(0为禁用)"; + }; + readonly "Memory cache": { + readonly def: "Memory cache"; + readonly es: "Caché en memoria"; + readonly ja: "メモリキャッシュ"; + readonly ko: "메모리 캐시"; + readonly ru: "Кэш в памяти"; + }; + readonly "Memory cache size (by total characters)": { + readonly def: "Memory cache size (by total characters)"; + readonly es: "Tamaño caché memoria (por caracteres)"; + readonly fr: "Taille du cache mémoire (par nombre total de caractères)"; + readonly he: "גודל מטמון זיכרון (לפי סה\"כ תווים)"; + readonly ja: "全体でキャッシュする文字数"; + readonly ko: "메모리 캐시 크기 (총 문자 수)"; + readonly ru: "Размер кэша памяти (по общему количеству символов)"; + readonly zh: "内存缓存大小(按总字符数)"; + }; + readonly "Memory cache size (by total items)": { + readonly def: "Memory cache size (by total items)"; + readonly es: "Tamaño caché memoria (por ítems)"; + readonly fr: "Taille du cache mémoire (par nombre total d'éléments)"; + readonly he: "גודל מטמון זיכרון (לפי סה\"כ פריטים)"; + readonly ja: "全体のキャッシュサイズ"; + readonly ko: "메모리 캐시 크기 (총 항목 수)"; + readonly ru: "Размер кэша памяти (по общему количеству элементов)"; + readonly zh: "内存缓存大小(按总项目数)"; + }; + readonly Merge: { + readonly def: "Merge"; + readonly es: "Fusionar"; + readonly ja: "マージ"; + readonly ko: "병합"; + readonly ru: "Объединить"; + readonly zh: "合并"; + }; + readonly "Minimum delay for batch database updating": { + readonly def: "Minimum delay for batch database updating"; + readonly es: "Retraso mínimo para actualización por lotes"; + readonly fr: "Délai minimum pour la mise à jour groupée de la base"; + readonly he: "עיכוב מינימלי לעדכון אצווה של מסד נתונים"; + readonly ja: "バッチデータベース更新の最小遅延"; + readonly ko: "일괄 데이터베이스 업데이트 최소 지연"; + readonly ru: "Минимальная задержка пакетного обновления базы данных"; + readonly zh: "批量数据库更新的最小延迟"; + }; + readonly "Minimum interval for syncing": { + readonly def: "Minimum interval for syncing"; + readonly fr: "Intervalle minimum pour la synchronisation"; + readonly he: "מרווח מינימלי לסנכרון"; + readonly ja: "同期間隔の最小値"; + readonly ko: "동기화 최소 간격"; + readonly ru: "Минимальный интервал синхронизации"; + readonly zh: "同步最小间隔"; + readonly "zh-tw": "同步最小間隔"; + }; + readonly "moduleCheckRemoteSize.logCheckingStorageSizes": { + readonly def: "Checking storage sizes"; + readonly es: "Comprobando tamaños de almacenamiento"; + readonly fr: "Vérification des tailles de stockage"; + readonly he: "בודק גדלי אחסון"; + readonly ja: "ストレージサイズを確認中"; + readonly ko: "스토리지 크기 확인 중"; + readonly ru: "Проверка размеров хранилища"; + readonly zh: "正在检查存储大小"; + }; + readonly "moduleCheckRemoteSize.logCurrentStorageSize": { + readonly def: "Remote storage size: ${measuredSize}"; + readonly es: "Tamaño del almacenamiento remoto: ${measuredSize}"; + readonly fr: "Taille du stockage distant : ${measuredSize}"; + readonly he: "גודל אחסון מרוחק: ${measuredSize}"; + readonly ja: "リモートストレージサイズ: ${measuredSize}"; + readonly ko: "원격 스토리지 크기: ${measuredSize}"; + readonly ru: "Размер удалённого хранилища: measuredSize"; + readonly zh: "远程存储大小:${measuredSize}"; + }; + readonly "moduleCheckRemoteSize.logExceededWarning": { + readonly def: "Remote storage size: ${measuredSize} exceeded ${notifySize}"; + readonly es: "Tamaño del almacenamiento remoto: ${measuredSize} superó ${notifySize}"; + readonly fr: "Taille du stockage distant : ${measuredSize} a dépassé ${notifySize}"; + readonly he: "גודל אחסון מרוחק: ${measuredSize} עלה על ${notifySize}"; + readonly ja: "リモートストレージサイズ: ${measuredSize} が ${notifySize} を超過しました"; + readonly ko: "원격 스토리지 크기: ${measuredSize}가 ${notifySize}를 초과했습니다"; + readonly ru: "Размер удалённого хранилища: measuredSize превысил notifySize"; + readonly zh: "远程存储大小:${measuredSize} 超过 ${notifySize}"; + }; + readonly "moduleCheckRemoteSize.logThresholdEnlarged": { + readonly def: "Threshold has been enlarged to ${size}MB"; + readonly es: "El umbral se ha ampliado a ${size}MB"; + readonly fr: "Le seuil a été augmenté à ${size} Mo"; + readonly he: "הסף הורחב ל-${size}MB"; + readonly ja: "しきい値が ${size}MB に設定されました"; + readonly ko: "임계값이 ${size}MB로 증가되었습니다"; + readonly ru: "Порог увеличен до sizeМБ"; + readonly zh: "阈值已扩大到 ${size}MB"; + }; + readonly "moduleCheckRemoteSize.msgConfirmRebuild": { + readonly def: "This may take a bit of a long time. Do you really want to rebuild everything now?"; + readonly es: "Esto puede llevar un poco de tiempo. ¿Realmente quieres reconstruir todo ahora?"; + readonly fr: "Cela peut prendre un certain temps. Voulez-vous vraiment tout reconstruire maintenant ?"; + readonly he: "פעולה זו עשויה לקחת זמן מה. האם אתה בטוח שברצונך לבנות מחדש עכשיו?"; + readonly ja: "これは少し時間がかかる場合があります。本当に今すべてを再構築しますか?"; + readonly ko: "시간이 꽤 오래 걸릴 수 있습니다. 정말 지금 모든 것을 재구축하시겠습니까?"; + readonly ru: "Это может занять некоторое время. Вы действительно хотите перестроить всё сейчас?"; + readonly zh: "这可能需要一些时间。您真的想现在重建所有内容吗?"; + }; + readonly "moduleCheckRemoteSize.msgDatabaseGrowing": { + readonly def: "**Your database is getting larger!** But do not worry, we can address it now. The time before running out of space on the remote storage.\n\n| Measured size | Configured size |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> If you have been using it for many years, there may be unreferenced chunks - that is, garbage - accumulating in the database. Therefore, we recommend rebuilding everything. It will probably become much smaller.\n>\n> If the volume of your vault is simply increasing, it is better to rebuild everything after organizing the files. Self-hosted LiveSync does not delete the actual data even if you delete it to speed up the process. It is roughly [documented](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md).\n>\n> If you don't mind the increase, you can increase the notification limit by 100MB. This is the case if you are running it on your own server. However, it is better to rebuild everything from time to time.\n>\n\n> [!WARNING]\n> If you perform rebuild everything, make sure all devices are synchronised. The plug-in will merge as much as possible, though.\n"; + readonly es: "**¡Tu base de datos está creciendo!** Pero no te preocupes, podemos abordarlo ahora. El tiempo antes de quedarse sin espacio en el almacenamiento remoto.\n\n| Tamaño medido | Tamaño configurado |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> Si lo has estado utilizando durante muchos años, puede haber fragmentos no referenciados - es decir, basura - acumulándose en la base de datos. Por lo tanto, recomendamos reconstruir todo. Probablemente se volverá mucho más pequeño.\n>\n> Si el volumen de tu bóveda simplemente está aumentando, es mejor reconstruir todo después de organizar los archivos. Self-hosted LiveSync no elimina los datos reales incluso si los eliminas para acelerar el proceso. Está aproximadamente [documentado](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md).\n>\n> Si no te importa el aumento, puedes aumentar el límite de notificación en 100 MB. Este es el caso si lo estás ejecutando en tu propio servidor. Sin embargo, es mejor reconstruir todo de vez en cuando.\n>\n\n> [!WARNING]\n> Si realizas la reconstrucción completa, asegúrate de que todos los dispositivos estén sincronizados. El complemento fusionará tanto como sea posible, sin embargo.\n"; + readonly fr: "**Votre base de données grossit !** Pas d'inquiétude, nous pouvons y remédier dès maintenant, avant de manquer d'espace sur le stockage distant.\n\n| Taille mesurée | Taille configurée |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> Si vous l'utilisez depuis de nombreuses années, il peut y avoir des fragments non référencés — des déchets, en somme — accumulés dans la base. Nous recommandons donc de tout reconstruire. Cela réduira probablement beaucoup la taille.\n>\n> Si le volume de votre coffre augmente simplement, il est préférable de tout reconstruire après avoir organisé les fichiers. Self-hosted LiveSync ne supprime pas réellement les données même si vous les effacez, afin d'accélérer le processus. Ceci est documenté grossièrement [ici](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md).\n>\n> Si cela ne vous dérange pas, vous pouvez augmenter la limite de notification de 100 Mo. C'est le cas si vous l'exécutez sur votre propre serveur. Il reste toutefois préférable de tout reconstruire de temps en temps.\n>\n\n> [!WARNING]\n> Si vous tout reconstruisez, assurez-vous que tous les appareils sont synchronisés. Le plug-in fusionnera autant que possible cependant.\n"; + readonly he: "**מסד הנתונים שלך הולך וגדל!** אל תדאג, אנחנו יכולים לטפל בזה עכשיו. הזמן שנשאר עד לאזול המקום באחסון המרוחק.\n\n| גודל נמדד | גודל מוגדר |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> אם אתה משתמש בפלאגין כבר שנים רבות, ייתכן שנצברו נתחים לא מקושרים — כלומר, זבל — במסד הנתונים. לכן, אנו ממליצים לבנות הכל מחדש. ככל הנראה מסד הנתונים יהיה קטן בהרבה לאחר מכן.\n>\n> אם נפח הכספת שלך פשוט גדל, עדיף לבנות מחדש לאחר ארגון הקבצים. Self-hosted LiveSync אינו מוחק נתונים בפועל גם כאשר אתה מוחק קבצים כדי להאיץ את התהליך. הדבר [מתועד בפירוט](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md).\n>\n> אם אינך מוטרד מהגידול, ניתן להגדיל את סף ההתראה ב-100MB. הדבר מתאים אם השרת הוא שלך. עם זאת, מומלץ לבנות מחדש מעת לעת.\n>\n\n> [!WARNING]\n> אם תבנה מחדש, ודא שכל המכשירים מסונכרנים. הפלאגין ינסה למזג כמה שניתן.\n"; + readonly ja: "**データベースが大きくなっています!** でも心配しないでください。リモートストレージの容量が不足する前に対応できます。\n\n| 測定サイズ | 設定サイズ |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> 長年使用している場合、参照されていないチャンク(つまりゴミ)がデータベースに蓄積している可能性があります。そのため、すべてを再構築することをお勧めします。おそらくかなり小さくなるでしょう。\n>\n> 単純に保管庫の容量が増えている場合は、事前にファイルを整理してからすべてを再構築するのが良いでしょう。Self-hosted LiveSyncは処理速度を上げるため、削除しても実際のデータを削除しません。これはおおまかに[documentation](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md)に記載されています。\n>\n> 増加を気にしない場合は、通知制限を100MB単位で増やすことができます。これは自分のサーバーで実行している場合に適しています。ただし、定期的にすべてを再構築する方が良いでしょう。\n>\n\n> [!WARNING]\n> すべてを再構築する場合は、すべてのデバイスが同期されていることを確認してください。もちろん、プラグインは可能な限り解決しようと努力はしますけど...\n"; + readonly ko: "**데이터베이스 용량이 점점 커지고 있습니다!** 하지만 걱정하지 마세요. 아직 원격 스토리지 공간이 완전히 부족해진 건 아닙니다.\n\n| 측정된 크기 | 설정된 한도 |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> 오랜 기간 사용했다면 참조되지 않는 청크, 즉 '쓰레기 데이터'가 쌓였을 수 있습니다. 이 경우 전체 재구성을 권장합니다. 용량이 훨씬 줄어들 수 있습니다.\n> \n> 단순히 볼트 자체 용량이 커지고 있는 것이라면, 먼저 파일을 정리한 후 전체를 재구성하는 것이 좋습니다. Self-hosted LiveSync는 처리 속도를 위해 삭제해도 실제 데이터를 바로 지우지 않습니다. 이 내용은 [기술 문서](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md)에 간략히 정리되어 있습니다.\n> \n> 용량 증가가 괜찮다면 알림 임계치를 100MB 단위로 높일 수 있습니다. 직접 서버를 운영하는 경우에 적합한 방법입니다. 다만, 가끔은 전체 재구성을 해주는 것이 바람직합니다.\n\n> [!WARNING]\n> 전체 재구성을 실행할 경우, 모든 기기가 반드시 동기화되어 있어야 합니다. 플러그인이 최대한 병합하려고 시도하긴 하지만 완전하지 않을 수 있습니다."; + readonly ru: "Ваша база данных увеличивается! Но не волнуйтесь, мы можем решить это сейчас."; + readonly zh: "**您的数据库正在变大!** 但别担心,我们现在可以解决它。在远程存储空间用完之前还有时间。\n\n| 测量大小 | 配置大小 |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> 如果您已经使用了很多年,数据库中可能会积累未引用的 chunks——也就是垃圾。因此,我们建议重建所有内容。它可能会变得小得多。\n> \n> 如果您的库容量只是在增加,最好在整理文件后重建所有内容。即使您为了加速过程删除了文件,Self-hosted LiveSync 也不会删除实际数据。这大致[有文档记录](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md)。\n> \n> 如果您不介意增加,可以将通知限制增加 100MB。如果您在自己的服务器上运行,就是这种情况。但是,最好还是不时地重建所有内容。\n> \n\n> [!WARNING]\n> 如果您执行重建所有内容,请确保所有设备都已同步。尽管如此,插件会尽可能地合并\n"; + }; + readonly "moduleCheckRemoteSize.msgSetDBCapacity": { + readonly def: "We can set a maximum database capacity warning, **to take action before running out of space on the remote storage**.\nDo you want to enable this?\n\n> [!MORE]-\n> - 0: Do not warn about storage size.\n> This is recommended if you have enough space on the remote storage especially you have self-hosted. And you can check the storage size and rebuild manually.\n> - 800: Warn if the remote storage size exceeds 800MB.\n> This is recommended if you are using fly.io with 1GB limit or IBM Cloudant.\n> - 2000: Warn if the remote storage size exceeds 2GB.\n\nIf we have reached the limit, we will be asked to enlarge the limit step by step.\n"; + readonly es: "Podemos configurar una advertencia de capacidad máxima de base de datos, **para tomar medidas antes de quedarse sin espacio en el almacenamiento remoto**.\n¿Quieres habilitar esto?\n\n> [!MORE]-\n> - 0: No advertir sobre el tamaño del almacenamiento.\n> Esto es recomendado si tienes suficiente espacio en el almacenamiento remoto, especialmente si lo tienes autoalojado. Y puedes comprobar el tamaño del almacenamiento y reconstruir manualmente.\n> - 800: Advertir si el tamaño del almacenamiento remoto supera los 800 MB.\n> Esto es recomendado si estás usando fly.io con un límite de 1 GB o IBM Cloudant.\n> - 2000: Advertir si el tamaño del almacenamiento remoto supera los 2 GB.\n\nSi hemos alcanzado el límite, se nos pedirá que aumentemos el límite paso a paso.\n"; + readonly fr: "Nous pouvons définir un avertissement de capacité maximale de la base de données, **afin d'agir avant de manquer d'espace sur le stockage distant**.\nVoulez-vous activer ceci ?\n\n> [!MORE]-\n> - 0 : Ne pas avertir sur la taille de stockage.\n> Recommandé si vous avez suffisamment d'espace sur le stockage distant, surtout en auto-hébergement. Vous pouvez vérifier la taille et reconstruire manuellement.\n> - 800 : Avertir si la taille du stockage distant dépasse 800 Mo.\n> Recommandé si vous utilisez fly.io avec une limite de 1 Go ou IBM Cloudant.\n> - 2000 : Avertir si la taille du stockage distant dépasse 2 Go.\n\nSi la limite est atteinte, il nous sera proposé de l'augmenter étape par étape.\n"; + readonly he: "ניתן להגדיר אזהרת קיבולת מקסימלית של מסד הנתונים, **כדי לנקוט פעולה לפני שנגמר המקום באחסון המרוחד**.\nהאם להפעיל זאת?\n\n> [!MORE]-\n> - 0: אל תזהיר על גודל האחסון.\n> מומלץ אם יש לך מספיק מקום באחסון המרוחד, בעיקר אם השרת הוא שלך. ניתן לבדוק את גודל האחסון ולבנות מחדש ידנית.\n> - 800: הזהר אם גודל האחסון המרוחד עולה על 800MB.\n> מומלץ אם אתה משתמש ב-fly.io עם מגבלת 1GB או ב-IBM Cloudant.\n> - 2000: הזהר אם גודל האחסון המרוחד עולה על 2GB.\n\nאם הגענו למגבלה, תתבקש להרחיב את הסף בהדרגה.\n"; + readonly ja: "リモートストレージの容量が不足する前に対策を講じるため、**最大データベース容量の警告**を設定できます。\nこれを有効にしますか?\n\n> [!MORE]-\n> - 0: ストレージサイズについて警告しない。\n> 自宅サーバーなど、リモートストレージに十分な容量がある場合に推奨されます。ストレージサイズを確認し、手動で再構築できます。\n> - 800: リモートストレージサイズが800MBを超えたら警告。\n> 1GB制限のfly.ioやIBM Cloudantを使用している場合に推奨されます。\n> - 2000: リモートストレージサイズが2GBを超えたら警告。\n\n制限に達した場合、段階的に制限を増やすよう求められます。\n"; + readonly ko: "**원격 스토리지 공간이 부족해지기 전에 미리 조치할 수 있도록** 데이터베이스 용량 경고를 설정할 수 있습니다.\n이 기능을 활성화하시겠습니까?\n\n> [!MORE]-\n> - 0: 스토리지 용량에 대한 경고 없음\n> 자체 서버를 사용하는 등 여유 공간이 충분한 경우에 권장됩니다. 스토리지 용량을 직접 확인하고 수동으로 재구성할 수 있습니다.\n> - 800: 원격 스토리지 용량이 800MB를 초과하면 경고\n> 1GB 제한이 있는 fly.io나 IBM Cloudant 사용 시 권장됩니다.\n> - 2000: 원격 스토리지 용량이 2GB를 초과하면 경고\n\n설정한 용량 한도에 도달하면, 단계적으로 경고 한도를 늘릴지 여부를 묻게 됩니다.\n"; + readonly ru: "Можно установить предупреждение о максимальной ёмкости базы данных."; + readonly zh: "我们可以设置一个最大数据库容量警告,**以便在远程存储空间耗尽前采取行动**。\n您想启用这个功能吗?\n\n> [!MORE]-\n> - 0: 不警告存储大小。\n> 如果您在远程存储(尤其是自托管)上有足够的空间,则推荐此选项。您可以手动检查存储大小并重建。\n> - 800: 如果远程存储大小超过 800MB 则发出警告。\n> 如果您使用的是 fly.io(1GB 限制) 或 IBM Cloudant,则推荐此选项。\n> - 2000: 如果远程存储大小超过 2GB 则发出警告。\n\n如果达到限制,系统会要求我们逐步增大限制\n"; + }; + readonly "moduleCheckRemoteSize.option2GB": { + readonly def: "2GB (Standard)"; + readonly es: "2GB (Estándar)"; + readonly fr: "2 Go (Standard)"; + readonly he: "2GB (סטנדרטי)"; + readonly ja: "2GB (標準)"; + readonly ko: "2GB (표준)"; + readonly ru: "2ГБ (Стандарт)"; + readonly zh: "2GB (标准)"; + }; + readonly "moduleCheckRemoteSize.option800MB": { + readonly def: "800MB (Cloudant, fly.io)"; + readonly es: "800MB (Cloudant, fly.io)"; + readonly fr: "800 Mo (Cloudant, fly.io)"; + readonly he: "800MB (Cloudant, fly.io)"; + readonly ja: "800MB (Cloudant, fly.io)"; + readonly ko: "800MB (Cloudant, fly.io)"; + readonly ru: "800МБ (Cloudant, fly.io)"; + readonly zh: "800MB (Cloudant, fly.io)"; + }; + readonly "moduleCheckRemoteSize.optionAskMeLater": { + readonly def: "Ask me later"; + readonly es: "Pregúntame más tarde"; + readonly fr: "Me demander plus tard"; + readonly he: "שאל מאוחר יותר"; + readonly ja: "後で確認する"; + readonly ko: "나중에 물어보기"; + readonly ru: "Спросить позже"; + readonly zh: "稍后问我"; + }; + readonly "moduleCheckRemoteSize.optionDismiss": { + readonly def: "Dismiss"; + readonly es: "Descartar"; + readonly fr: "Ignorer"; + readonly he: "דחה"; + readonly ja: "無視"; + readonly ko: "무시"; + readonly ru: "Отклонить"; + readonly zh: "忽略"; + }; + readonly "moduleCheckRemoteSize.optionIncreaseLimit": { + readonly def: "increase to ${newMax}MB"; + readonly es: "aumentar a ${newMax}MB"; + readonly fr: "augmenter à ${newMax} Mo"; + readonly he: "הגדל ל-${newMax}MB"; + readonly ja: "${newMax}MBに設定"; + readonly ko: "${newMax}MB로 증가"; + readonly ru: "увеличить до newMaxМБ"; + readonly zh: "增加到 ${newMax}MB"; + }; + readonly "moduleCheckRemoteSize.optionNoWarn": { + readonly def: "No, never warn please"; + readonly es: "No, nunca advertir por favor"; + readonly fr: "Non, ne jamais avertir"; + readonly he: "לא, אל תזהיר בכלל"; + readonly ja: "いいえ、警告しないでください"; + readonly ko: "아니요, 경고하지 마세요"; + readonly ru: "Нет, не уведомлять"; + readonly zh: "不,请永远不要警告"; + }; + readonly "moduleCheckRemoteSize.optionRebuildAll": { + readonly def: "Rebuild Everything Now"; + readonly es: "Reconstruir todo ahora"; + readonly fr: "Tout reconstruire maintenant"; + readonly he: "בנה הכל מחדש עכשיו"; + readonly ja: "今すべてを再構築"; + readonly ko: "지금 모든 것 재구축"; + readonly ru: "Перестроить всё сейчас"; + readonly zh: "立即重建所有内容"; + }; + readonly "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": { + readonly def: "Remote storage size exceeded the limit"; + readonly es: "El tamaño del almacenamiento remoto superó el límite"; + readonly fr: "Taille du stockage distant au-delà de la limite"; + readonly he: "גודל האחסון המרוחד חרג מהמגבלה"; + readonly ja: "リモートストレージサイズが制限を超過しました"; + readonly ko: "원격 스토리지 크기가 제한을 초과했습니다"; + readonly ru: "Размер удалённого хранилища превысил лимит"; + readonly zh: "远程存储大小超出限制"; + }; + readonly "moduleCheckRemoteSize.titleDatabaseSizeNotify": { + readonly def: "Setting up database size notification"; + readonly es: "Configuración de notificación de tamaño de base de datos"; + readonly fr: "Configuration de la notification de taille de base"; + readonly he: "הגדרת התראה על גודל מסד נתונים"; + readonly ja: "データベースサイズ通知の設定"; + readonly ko: "데이터베이스 크기 알림 설정"; + readonly ru: "Настройка уведомления о размере базы данных"; + readonly zh: "设置数据库大小通知"; + }; + readonly "moduleInputUIObsidian.defaultTitleConfirmation": { + readonly def: "Confirmation"; + readonly es: "Confirmación"; + readonly fr: "Confirmation"; + readonly he: "אישור"; + readonly ja: "確認"; + readonly ko: "확인"; + readonly ru: "Подтверждение"; + readonly zh: "确认"; + }; + readonly "moduleInputUIObsidian.defaultTitleSelect": { + readonly def: "Select"; + readonly es: "Seleccionar"; + readonly fr: "Sélection"; + readonly he: "בחר"; + readonly ja: "選択"; + readonly ko: "선택"; + readonly ru: "Выбор"; + readonly zh: "选择"; + }; + readonly "moduleInputUIObsidian.optionNo": { + readonly def: "No"; + readonly es: "No"; + readonly fr: "Non"; + readonly he: "לא"; + readonly ja: "いいえ"; + readonly ko: "아니요"; + readonly ru: "Нет"; + readonly zh: "否"; + }; + readonly "moduleInputUIObsidian.optionYes": { + readonly def: "Yes"; + readonly es: "Sí"; + readonly fr: "Oui"; + readonly he: "כן"; + readonly ja: "はい"; + readonly ko: "예"; + readonly ru: "Да"; + readonly zh: "是"; + }; + readonly "moduleLiveSyncMain.logAdditionalSafetyScan": { + readonly def: "Additional safety scan..."; + readonly es: "Escanéo de seguridad adicional..."; + readonly fr: "Analyse de sécurité supplémentaire..."; + readonly he: "סריקת בטיחות נוספת..."; + readonly ja: "追加の安全スキャン中..."; + readonly ko: "추가 안전 검사 중..."; + readonly ru: "Дополнительная проверка безопасности..."; + readonly zh: "额外的安全扫描..."; + }; + readonly "moduleLiveSyncMain.logLoadingPlugin": { + readonly def: "Loading plugin..."; + readonly es: "Cargando complemento..."; + readonly fr: "Chargement du plugin..."; + readonly he: "טוען תוסף..."; + readonly ja: "プラグインをロード中..."; + readonly ko: "플러그인 로딩 중..."; + readonly ru: "Загрузка плагина..."; + readonly zh: "正在加载插件..."; + }; + readonly "moduleLiveSyncMain.logPluginInitCancelled": { + readonly def: "Plugin initialisation was cancelled by a module"; + readonly es: "La inicialización del complemento fue cancelada por un módulo"; + readonly fr: "L'initialisation du plugin a été annulée par un module"; + readonly he: "אתחול התוסף בוטל על ידי מודול"; + readonly ja: "プラグインの初期化がモジュールによってキャンセルされました"; + readonly ko: "모듈에 의해 플러그인 초기화가 취소되었습니다"; + readonly ru: "Инициализация плагина отменена модулем"; + readonly zh: "插件初始化被某个模块取消"; + }; + readonly "moduleLiveSyncMain.logPluginVersion": { + readonly def: "Self-hosted LiveSync v${manifestVersion} ${packageVersion}"; + readonly es: "Self-hosted LiveSync v${manifestVersion} ${packageVersion}"; + readonly fr: "Self-hosted LiveSync v${manifestVersion} ${packageVersion}"; + readonly he: "Self-hosted LiveSync גרסה ${manifestVersion} ${packageVersion}"; + readonly ja: "Self-hosted LiveSync v${manifestVersion} ${packageVersion}"; + readonly ko: "Self-hosted LiveSync v${manifestVersion} ${packageVersion}"; + readonly ru: "Self-hosted LiveSync vmanifestVersion packageVersion"; + readonly zh: "Self-hosted LiveSync v${manifestVersion} ${packageVersion}"; + }; + readonly "moduleLiveSyncMain.logReadChangelog": { + readonly def: "LiveSync has updated, please read the changelog!"; + readonly es: "LiveSync se ha actualizado, ¡por favor lee el registro de cambios!"; + readonly fr: "LiveSync a été mis à jour, veuillez lire le journal des modifications !"; + readonly he: "LiveSync עודכן, אנא קרא את יומן השינויים!"; + readonly ja: "LiveSyncが更新されました。変更履歴をお読みください!"; + readonly ko: "LiveSync가 업데이트되었습니다. 변경사항을 읽어보세요!"; + readonly ru: "LiveSync обновлён, пожалуйста, прочитайте список изменений!"; + readonly zh: "LiveSync 已更新,请阅读更新日志!"; + }; + readonly "moduleLiveSyncMain.logSafetyScanCompleted": { + readonly def: "Additional safety scan completed"; + readonly es: "Escanéo de seguridad adicional completado"; + readonly fr: "Analyse de sécurité supplémentaire terminée"; + readonly he: "סריקת הבטיחות הנוספת הושלמה"; + readonly ja: "追加の安全スキャンが完了しました"; + readonly ko: "추가 안전 검사가 완료되었습니다"; + readonly ru: "Дополнительная проверка безопасности завершена"; + readonly zh: "额外的安全扫描完成"; + }; + readonly "moduleLiveSyncMain.logSafetyScanFailed": { + readonly def: "Additional safety scan has failed on a module"; + readonly es: "El escaneo de seguridad adicional ha fallado en un módulo"; + readonly fr: "L'analyse de sécurité supplémentaire a échoué sur un module"; + readonly he: "סריקת הבטיחות הנוספת נכשלה במודול"; + readonly ja: "モジュールで追加の安全スキャンが失敗しました"; + readonly ko: "모듈에서 추가 안전 검사가 실패했습니다"; + readonly ru: "Дополнительная проверка безопасности не удалась в модуле"; + readonly zh: "额外的安全扫描在某个模块上失败"; + }; + readonly "moduleLiveSyncMain.logUnloadingPlugin": { + readonly def: "Unloading plugin..."; + readonly es: "Descargando complemento..."; + readonly fr: "Déchargement du plugin..."; + readonly he: "מסיר תוסף..."; + readonly ja: "プラグインをアンロード中..."; + readonly ko: "플러그인 언로딩 중..."; + readonly ru: "Выгрузка плагина..."; + readonly zh: "正在卸载插件..."; + }; + readonly "moduleLiveSyncMain.logVersionUpdate": { + readonly def: "LiveSync has been updated, In case of breaking updates, all automatic synchronization has been temporarily disabled. Ensure that all devices are up to date before enabling."; + readonly es: "LiveSync se ha actualizado, en caso de actualizaciones que rompan, toda la sincronización automática se ha desactivado temporalmente. Asegúrate de que todos los dispositivos estén actualizados antes de habilitar."; + readonly fr: "LiveSync a été mis à jour. En cas de mises à jour non rétrocompatibles, toute synchronisation automatique a été temporairement désactivée. Assurez-vous que tous les appareils sont à jour avant d'activer."; + readonly he: "LiveSync עודכן. במקרה של עדכונים משמעותיים, כל הסנכרון האוטומטי הושבת זמנית. ודא שכל המכשירים מעודכנים לפני ההפעלה."; + readonly ja: "LiveSyncが更新されました。互換性のない更新の場合、すべての自動同期が一時的に無効化されています。有効にする前に、すべてのデバイスが最新の状態であることを確認してください。"; + readonly ko: "LiveSync가 업데이트되었습니다. 호환성 문제가 있는 업데이트의 경우 모든 자동 동기화가 일시적으로 비활성화되었습니다. 활성화하기 전에 모든 기기가 최신 상태인지 확인하세요."; + readonly ru: "LiveSync обновлён. В случае критических изменений автоматическая синхронизация временно отключена. Убедитесь, что все устройства обновлены перед включением."; + readonly zh: "LiveSync 已更新,如果存在破坏性更新,所有自动同步已暂时禁用。请确保所有设备都更新到最新版本后再启用"; + }; + readonly "moduleLiveSyncMain.msgScramEnabled": { + readonly def: "Self-hosted LiveSync has been configured to ignore some events. Is this correct?\n\n| Type | Status | Note |\n|:---:|:---:|---|\n| Storage Events | ${fileWatchingStatus} | Every modification will be ignored |\n| Database Events | ${parseReplicationStatus} | Every synchronised change will be postponed |\n\nDo you want to resume them and restart Obsidian?\n\n> [!DETAILS]-\n> These flags are set by the plug-in while rebuilding, or fetching. If the process ends abnormally, it may be kept unintended.\n> If you are not sure, you can try to rerun these processes. Make sure to back your vault up.\n"; + readonly es: "Self-hosted LiveSync se ha configurado para ignorar algunos eventos. ¿Es esto correcto?\n\n| Tipo | Estado | Nota |\n|:---:|:---:|---|\n| Eventos de almacenamiento | ${fileWatchingStatus} | Se ignorará cada modificación |\n| Eventos de base de datos | ${parseReplicationStatus} | Cada cambio sincronizado se pospondrá |\n\n¿Quieres reanudarlos y reiniciar Obsidian?\n\n> [!DETAILS]-\n> Estas banderas son establecidas por el complemento mientras se reconstruye o se obtiene. Si el proceso termina de forma anormal, puede mantenerse sin querer.\n> Si no estás seguro, puedes intentar volver a ejecutar estos procesos. Asegúrate de hacer una copia de seguridad de tu bóveda.\n"; + readonly fr: "Self-hosted LiveSync a été configuré pour ignorer certains événements. Est-ce correct ?\n\n| Type | Statut | Note |\n|:---:|:---:|---|\n| Événements de stockage | ${fileWatchingStatus} | Toute modification sera ignorée |\n| Événements de base | ${parseReplicationStatus} | Tout changement synchronisé sera reporté |\n\nVoulez-vous les reprendre et redémarrer Obsidian ?\n\n> [!DETAILS]-\n> Ces indicateurs sont définis par le plug-in lors d'une reconstruction ou d'une récupération. Si le processus se termine anormalement, ils peuvent rester activés involontairement.\n> Si vous n'êtes pas certain, vous pouvez relancer ces processus. Veillez à sauvegarder votre coffre.\n"; + readonly he: "Self-hosted LiveSync הוגדר להתעלם מאירועים מסוימים. האם זה נכון?\n\n| סוג | סטטוס | הערה |\n|:---:|:---:|---|\n| אירועי אחסון | ${fileWatchingStatus} | כל שינוי יתעלם |\n| אירועי מסד נתונים | ${parseReplicationStatus} | כל שינוי מסונכרן יידחה |\n\nהאם לחדש אותם ולהפעיל מחדש את Obsidian?\n\n> [!DETAILS]-\n> דגלים אלה מוגדרים על ידי הפלאגין במהלך בנייה מחדש או משיכה. אם התהליך הסתיים בצורה לא תקינה, ייתכן שהם נשארו כלא מכוון.\n> אם אינך בטוח, ניתן לנסות להריץ מחדש את התהליכים. ודא שיש לך גיבוי של הכספת.\n"; + readonly ja: "Self-hosted LiveSyncは一部のイベントを無視するように設定されています。これは正しいですか?\n\n| タイプ | ステータス | メモ |\n|:---:|:---:|---|\n| ストレージイベント | ${fileWatchingStatus} | すべての変更が無視されます |\n| データベースイベント | ${parseReplicationStatus} | すべての同期された変更が延期されます |\n\nこれらを再開してObsidianを再起動しますか?\n\n> [!DETAILS]-\n> これらのフラグは、プラグインが再構築またはフェッチ中に設定されます。プロセスが異常終了した場合、意図せず保持されることがあります。\n> 不明な場合は、これらのプロセスを再実行してみてください。必ず保管庫をバックアップしてください。\n"; + readonly ko: "Self-hosted LiveSync가 일부 이벤트를 무시하도록 설정되어 있습니다. 이 설정이 맞습니까?\n\n| 유형 | 상태 | 설명 |\n|:---:|:---:|---|\n| 스토리지 이벤트 | ${fileWatchingStatus} | 모든 수정 사항이 무시됩니다 |\n| 데이터베이스 이벤트 | ${parseReplicationStatus} | 모든 동기화 변경이 지연됩니다 |\n\n이벤트 감지를 다시 활성화하고 Obsidian을 재시작하시겠습니까?\n\n> [!DETAILS]-\n> 이러한 설정은 플러그인이 재구성 또는 데이터 가져오기 중에 자동으로 설정한 것입니다. 프로세스가 비정상적으로 종료되면 이 상태가 의도치 않게 유지될 수 있습니다.\n> 상태가 확실하지 않다면 이 과정을 다시 실행해 보세요. 재시작 전에 반드시 볼트를 백업해 주세요."; + readonly ru: "Self-hosted LiveSync has been configured to ignore some events. Is this correct?\n\n| Type | Status | Note |\n|:---:|:---:|---|\n| Storage Events | ${fileWatchingStatus} | Every modification will be ignored |\n| Database Events | ${parseReplicationStatus} | Every synchronised change will be postponed |\n\nDo you want to resume them and restart Obsidian?\n\n> [!DETAILS]-\n> These flags are set by the plug-in while rebuilding, or fetching. If the process ends abnormally, it may be kept unintended.\n> If you are not sure, you can try to rerun these processes. Make sure to back your vault up.\n"; + readonly zh: "Self-hosted LiveSync 已被配置为忽略某些事件。这样对吗?\n\n| 类型 | 状态 | 说明 |\n|:---:|:---:|---|\n| 存储事件 | ${fileWatchingStatus} | 所有修改都将被忽略 |\n| 数据库事件 | ${parseReplicationStatus} | 所有同步的更改都将被推迟 |\n\n您想恢复它们并重启 Obsidian 吗?\n\n> [!DETAILS]-\n> 这些标志是在重建或获取时由插件设置的。如果过程异常结束,它们可能会被无意中保留。\n> 如果您不确定,可以尝试重新运行这些过程。请确保备份您的库。\n"; + }; + readonly "moduleLiveSyncMain.optionKeepLiveSyncDisabled": { + readonly def: "Keep LiveSync disabled"; + readonly es: "Mantener LiveSync desactivado"; + readonly fr: "Garder LiveSync désactivé"; + readonly he: "השאר LiveSync מנוטרל"; + readonly ja: "LiveSyncを無効のままにする"; + readonly ko: "LiveSync 비활성화 유지"; + readonly ru: "Оставить LiveSync отключённым"; + readonly zh: "保持 LiveSync 禁用"; + }; + readonly "moduleLiveSyncMain.optionResumeAndRestart": { + readonly def: "Resume and restart Obsidian"; + readonly es: "Reanudar y reiniciar Obsidian"; + readonly fr: "Reprendre et redémarrer Obsidian"; + readonly he: "חדש והפעל מחדש את Obsidian"; + readonly ja: "再開してObsidianを再起動"; + readonly ko: "재개 후 Obsidian 재시작"; + readonly ru: "Продолжить и перезапустить Obsidian"; + readonly zh: "恢复并重启 Obsidian"; + }; + readonly "moduleLiveSyncMain.titleScramEnabled": { + readonly def: "Scram Enabled"; + readonly es: "Scram habilitado"; + readonly fr: "Mode Scram activé"; + readonly he: "מצב בלימה פעיל"; + readonly ja: "緊急停止(Scram)が有効"; + readonly ko: "Scram 활성화됨"; + readonly ru: "Экстренная остановка включена"; + readonly zh: "紧急停止已启用"; + }; + readonly "moduleLocalDatabase.logWaitingForReady": { + readonly def: "Waiting for ready..."; + readonly es: "Esperando a que la base de datos esté lista..."; + readonly fr: "En attente de disponibilité..."; + readonly he: "ממתין לכשירות..."; + readonly ja: "しばらくお待ちください..."; + readonly ko: "준비 대기 중..."; + readonly ru: "Ожидание готовности..."; + readonly zh: "等待就绪..."; + }; + readonly "moduleLog.showLog": { + readonly def: "Show Log"; + readonly es: "Mostrar registro"; + readonly fr: "Afficher le journal"; + readonly he: "הצג יומן"; + readonly ja: "ログを表示"; + readonly ko: "로그 표시"; + readonly ru: "Показать лог"; + readonly zh: "显示日志"; + }; + readonly "moduleMigration.docUri": { + readonly def: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use"; + readonly es: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README_ES.md#how-to-use"; + readonly fr: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use"; + readonly he: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use"; + readonly ja: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use"; + readonly ko: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use"; + readonly ru: "https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use"; + readonly zh: "https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/zh/README_zh.md#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8"; + }; + readonly "moduleMigration.fix0256.buttons.checkItLater": { + readonly def: "Check it later"; + readonly fr: "Vérifier plus tard"; + readonly he: "בדוק מאוחר יותר"; + readonly ja: "後で確認する"; + readonly ru: "Проверить позже"; + readonly zh: "稍后检查"; + }; + readonly "moduleMigration.fix0256.buttons.DismissForever": { + readonly def: "I have fixed it, and do not ask again"; + readonly fr: "J'ai corrigé, et ne plus demander"; + readonly he: "תיקנתי, ואל תשאל שוב"; + readonly ja: "修正済み、今後確認しない"; + readonly ru: "Исправлено, больше не спрашивать"; + readonly zh: "我已经修复了,不再询问"; + }; + readonly "moduleMigration.fix0256.buttons.fix": { + readonly def: "Fix"; + readonly fr: "Corriger"; + readonly he: "תקן"; + readonly ja: "修正"; + readonly ru: "Исправить"; + readonly zh: "修复"; + }; + readonly "moduleMigration.fix0256.message": { + readonly def: "Due to a recent bug (in v0.25.6), some files may not have been saved correctly in the sync database.\nWe have scanned our files and found some that need to be fixed.\n\n**Files ready to be fixed:**\n\n${files}\n\nThese files have size-matched original file on the storage, and are likely to be recoverable.\nWe can use them to fix the database, please click the \"Fix\" button below to fix them.\n\n${messageUnrecoverable}\n\nIf you want to run it again, you can do so from Hatch.\n"; + readonly fr: "En raison d'un bug récent (en v0.25.6), certains fichiers peuvent ne pas avoir été enregistrés correctement dans la base de synchronisation.\nNous avons analysé vos fichiers et trouvé ceux à corriger.\n\n**Fichiers prêts à être corrigés :**\n\n${files}\n\nCes fichiers ont un original de taille correspondante sur le stockage, et sont probablement récupérables.\nNous pouvons les utiliser pour corriger la base, veuillez cliquer sur le bouton « Corriger » ci-dessous pour les réparer.\n\n${messageUnrecoverable}\n\nSi vous voulez relancer l'opération, vous pouvez le faire depuis Hatch.\n"; + readonly he: "בשל באג אחרון (בגרסה 0.25.6), ייתכן שחלק מהקבצים לא נשמרו כהלכה במסד הנתונים לסנכרון.\nסרקנו את הקבצים ומצאנו כאלה שיש לתקן.\n\n**קבצים מוכנים לתיקון:**\n\n${files}\n\nלקבצים אלה יש קובץ מקורי תואם גודל באחסון, וסביר שניתן לשחזרם.\nניתן להשתמש בהם לתיקון מסד הנתונים. לחץ על כפתור \"תקן\" למטה לתיקון.\n\n${messageUnrecoverable}\n\nאם ברצונך להריץ שוב, ניתן לעשות זאת מ-Hatch.\n"; + readonly ja: "最近のバグ(v0.25.6)により、一部のファイルが同期データベースに正しく保存されていない可能性があります。\nファイルをスキャンし、修正が必要なものが見つかりました。\n\n**修正準備ができたファイル:**\n\n${files}\n\nこれらのファイルはストレージ上の元ファイルとサイズが一致しており、復元可能です。\n「修正」ボタンをクリックしてデータベースを修正できます。\n\n${messageUnrecoverable}\n\n再実行したい場合は、Hatchから実行できます。\n"; + readonly ru: "Из-за недавней ошибки некоторые файлы могут быть неправильно сохранены."; + readonly zh: "由于最近的一个 bug(在 v0.25.6 版本中),某些文件可能未正确保存到同步数据库中\n我们已经扫描了文件,并发现一些需要修复的文件\n\n**准备修复的文件:**\n\n${files}\n\n这些文件在存储中与原文件的大小匹配,可能是可恢复的\n我们可以使用它们修复数据库,请点击下方的“修复”按钮进行修复\n\n${messageUnrecoverable}\n\n\n如果你希望再次执行此操作,可以前往 Hatch 页面进行操作\n"; + }; + readonly "moduleMigration.fix0256.messageUnrecoverable": { + readonly def: "**Files cannot be fixed on this device:**\n\n${filesNotRecoverable}\n\nThese files have inconsistent metadata, and cannot be fixed on this device (mostly we cannot determine which is correct).\nTo restore them, please check your other devices (also by this feature) or restore them manually from a backup.\n"; + readonly fr: "**Fichiers non réparables sur cet appareil :**\n\n${filesNotRecoverable}\n\nCes fichiers ont des métadonnées incohérentes et ne peuvent être corrigés sur cet appareil (le plus souvent, nous ne pouvons déterminer lequel est correct).\nPour les restaurer, vérifiez vos autres appareils (par cette même fonction) ou restaurez-les manuellement depuis une sauvegarde.\n"; + readonly he: "**קבצים שלא ניתן לתקן במכשיר זה:**\n\n${filesNotRecoverable}\n\nלקבצים אלה יש מטה-נתונים לא עקביים, ולא ניתן לתקנם במכשיר זה (לרוב לא ניתן לקבוע מה נכון). לשחזורם, אנא בדוק מכשירים אחרים שלך (גם בתכונה זו) או שחזר ידנית מגיבוי.\n"; + readonly ja: "**このデバイスで修正できないファイル:**\n\n${filesNotRecoverable}\n\nこれらのファイルはメタデータに不整合があり、このデバイスでは修正できません(ほとんどの場合、どちらが正しいか判定できません)。\n復元するには、他のデバイスで確認するか、バックアップから手動で復元してください。\n"; + readonly ru: "Файлы не могут быть исправлены на этом устройстве:"; + readonly zh: "**无法在此设备上修复的文件:**\n\n${filesNotRecoverable}\n\n这些文件的元数据不一致,无法在此设备上修复(大多数情况下我们无法确定哪一个是正确的)\n要恢复它们,请检查你的其他设备(同样使用此功能),或从备份中手动恢复\n"; + }; + readonly "moduleMigration.fix0256.title": { + readonly def: "Broken files has been detected"; + readonly fr: "Fichiers corrompus détectés"; + readonly he: "זוהו קבצים פגומים"; + readonly ja: "破損ファイルが検出されました"; + readonly ru: "Обнаружены повреждённые файлы"; + readonly zh: "检测到损坏的文件"; + }; + readonly "moduleMigration.insecureChunkExist.buttons.fetch": { + readonly def: "I already rebuilt the remote. Fetch from the remote"; + readonly fr: "J'ai déjà reconstruit le distant. Récupérer depuis le distant"; + readonly he: "כבר בניתי מחדש את השרת המרוחק. משוך מהשרת המרוחד"; + readonly ja: "リモートを既に再構築した。リモートからフェッチ"; + readonly ru: "Я уже перестроил удалённую. Загрузить с удалённой"; + readonly zh: "我已经重建了远程数据库,将从远程获取"; + }; + readonly "moduleMigration.insecureChunkExist.buttons.later": { + readonly def: "I will do it later"; + readonly fr: "Je le ferai plus tard"; + readonly he: "אטפל בזה מאוחר יותר"; + readonly ja: "後で行う"; + readonly ru: "Сделаю позже"; + readonly zh: "我稍后再做"; + }; + readonly "moduleMigration.insecureChunkExist.buttons.rebuild": { + readonly def: "Rebuild Everything"; + readonly fr: "Tout reconstruire"; + readonly he: "בנה הכל מחדש"; + readonly ja: "すべてを再構築"; + readonly ru: "Перестроить всё"; + readonly zh: "重建所有内容"; + }; + readonly "moduleMigration.insecureChunkExist.laterMessage": { + readonly def: "We strongly recommend to treat this as soon as possible!"; + readonly fr: "Nous recommandons fortement de traiter ceci dès que possible !"; + readonly he: "אנו ממליצים בחום לטפל בזה בהקדם האפשרי!"; + readonly ja: "できるだけ早く対処することを強くお勧めします!"; + readonly ru: "Мы настоятельно рекомендуем обработать это как можно скорее!"; + readonly zh: "我们强烈建议尽快处理此问题!"; + }; + readonly "moduleMigration.insecureChunkExist.message": { + readonly def: "Some chunks are not securely stored and are not encrypted in databases.\n**Please rebuild the database to fix this issue**.\n\nIf your Remote Database is not configured with SSL, or using less-secure credentials, **you are at risk of exposing sensitive data**.\n\nNote: Please upgrade your Self-hosted LiveSync v0.25.6 or higher on all your devices, and back your vault up surely.\nNote2: Rebuild Everything and Fetch consumes a bit of time and traffic, please do it in off-peak hours and ensure a stable network connection.\n"; + readonly fr: "Certains fragments ne sont pas stockés de façon sécurisée et ne sont pas chiffrés dans les bases.\n**Veuillez reconstruire la base pour corriger ce problème.**\n\nSi votre base distante n'est pas configurée avec SSL, ou utilise des identifiants peu sûrs, **vous risquez d'exposer des données sensibles**.\n\nNote : Veuillez mettre à jour Self-hosted LiveSync en v0.25.6 ou supérieur sur tous vos appareils, et sauvegardez votre coffre avec soin.\nNote 2 : Tout reconstruire et Récupérer consomme un peu de temps et de bande passante, veuillez le faire hors des heures de pointe et avec une connexion réseau stable.\n"; + readonly he: "חלק מהנתחים לא מאוחסנים בצורה מאובטחת ואינם מוצפנים במסד הנתונים.\n**אנא בנה מחדש את מסד הנתונים כדי לתקן בעיה זו**.\n\nאם מסד הנתונים המרוחד אינו מוגדר עם SSL, או משתמש בפרטי גישה פחות מאובטחים, **אתה בסיכון של חשיפת מידע רגיש**.\n\nהערה: אנא שדרג את Self-hosted LiveSync לגרסה 0.25.6 ומעלה על כל מכשיריך, וגבה את הכספת שלך.\nהערה 2: בנייה מחדש ומשיכה דורשות זמן ותעבורת רשת. אנא עשה זאת בשעות שיא נמוך וודא חיבור רשת יציב.\n"; + readonly ja: "一部のチャンクが安全に保存されておらず、データベースで暗号化されていません。\n**この問題を修正するにはデータベースを再構築してください**。\n\nリモートデータベースがSSLで設定されていない、または安全性の低い認証情報を使用している場合、**機密データが漏洩するリスクがあります**。\n\n注意: すべてのデバイスでSelf-hosted LiveSync v0.25.6以降にアップグレードし、必ず保管庫をバックアップしてください。\n注意2: すべてを再構築とフェッチは時間とトラフィックを消費します。オフピーク時間に安定したネットワークで実行してください。\n"; + readonly ru: "Некоторые чанки хранятся небезопасно. Пожалуйста, перестройте базу данных."; + readonly zh: "一些块未安全存储,并且在数据库中未加密\n**请重建数据库以修复此问题**.\n\n如果你的远程数据库未配置 SSL,或者使用了不安全的凭据 **你可能面临暴露敏感数据的风险**.\n\n注意:请在所有设备上将 Self-hosted LiveSync 升级到 v0.25.6 或更高版本,并确保备份你的保险库\n\n注意2:重建所有内容和获取操作会消耗一些时间和流量,请在非高峰时段进行,并确保网络连接稳定\n"; + }; + readonly "moduleMigration.insecureChunkExist.title": { + readonly def: "Insecure chunks found!"; + readonly fr: "Fragments non sécurisés détectés !"; + readonly he: "נמצאו נתחים לא מאובטחים!"; + readonly ja: "安全でないチャンクが見つかりました!"; + readonly ru: "Обнаружены небезопасные чанки!"; + readonly zh: "发现不安全的块!"; + }; + readonly "moduleMigration.logBulkSendCorrupted": { + readonly def: "Send chunks in bulk has been enabled, however, this feature had been corrupted. Sorry for your inconvenience. Automatically disabled."; + readonly es: "El envío de fragmentos en bloque se ha habilitado, sin embargo, esta función se ha corrompido. Disculpe las molestias. Deshabilitado automáticamente."; + readonly fr: "L'envoi groupé de fragments a été activé, mais cette fonctionnalité était corrompue. Désolé pour la gêne. Désactivée automatiquement."; + readonly he: "שליחת נתחים באצווה הופעלה, אך תכונה זו הייתה פגועה. מתנצלים על אי הנוחות. נוטרלה אוטומטית."; + readonly ja: "チャンクの一括送信が有効にされていましたが、この機能に問題がありました。ご不便をおかけして申し訳ありません。自動的に無効化されました。"; + readonly ko: "청크 일괄 전송이 활성화되었지만, 이 기능에 문제가 있었습니다. 불편을 드려 죄송합니다. 자동으로 비활성화되었습니다."; + readonly ru: "Отправка чанков пакетами была включена, но эта функция была повреждена. Приносим извинения. Автоматически отключено."; + readonly zh: "已启用批量发送 chunks,但此功能已损坏。给您带来不便,我们深表歉意。已自动禁用"; + }; + readonly "moduleMigration.logFetchRemoteTweakFailed": { + readonly def: "Failed to fetch remote tweak values"; + readonly es: "Error al obtener los valores de ajuste remoto"; + readonly fr: "Échec de la récupération des valeurs d'ajustement distantes"; + readonly he: "נכשל במשיכת ערכי כיוונון מרוחקים"; + readonly ja: "リモートの調整値の取得に失敗しました"; + readonly ko: "원격 조정 값을 가져오는데 실패했습니다"; + readonly ru: "Не удалось загрузить удалённые настройки"; + readonly zh: "获取远程调整值失败"; + }; + readonly "moduleMigration.logLocalDatabaseNotReady": { + readonly def: "Something went wrong! The local database is not ready"; + readonly es: "¡Algo salió mal! La base de datos local no está lista"; + readonly fr: "Un problème est survenu ! La base locale n'est pas prête"; + readonly he: "משהו השתבש! מסד הנתונים המקומי אינו מוכן"; + readonly ja: "何か問題が発生しました!ローカルデータベースが準備できていません"; + readonly ko: "문제가 발생했습니다! 로컬 데이터베이스가 준비되지 않았습니다"; + readonly ru: "Что-то пошло не так! Локальная база данных не готова"; + readonly zh: "出错了!本地数据库尚未准备好"; + }; + readonly "moduleMigration.logMigratedSameBehaviour": { + readonly def: "Migrated to db:${current} with the same behaviour as before"; + readonly es: "Migrado a db:${current} con el mismo comportamiento que antes"; + readonly fr: "Migration vers db:${current} avec le même comportement qu'auparavant"; + readonly he: "הוגר ל-db:${current} עם אותה התנהגות כמקודם"; + readonly ja: "以前と同じ動作でdb:${current}に移行しました"; + readonly ko: "이전과 같은 방식으로 동작하도록 db:${current}로 데이터 구조 전환이 완료되었습니다"; + readonly ru: "Миграция на db:current с тем же поведением, что и раньше"; + readonly zh: "已迁移到 db:${current},行为与之前相同"; + }; + readonly "moduleMigration.logMigrationFailed": { + readonly def: "Migration failed or cancelled from ${old} to ${current}"; + readonly es: "La migración falló o se canceló de ${old} a ${current}"; + readonly fr: "Migration échouée ou annulée de ${old} vers ${current}"; + readonly he: "הגירה נכשלה או בוטלה מ-${old} ל-${current}"; + readonly ja: "${old}から${current}への移行が失敗またはキャンセルされました"; + readonly ko: "${old}에서 ${current}로의 데이터 구조 전환이 실패했거나 중단되었습니다"; + readonly ru: "Миграция не удалась или отменена с old на current"; + readonly zh: "从 ${old} 到 ${current} 的迁移失败或已取消"; + }; + readonly "moduleMigration.logRedflag2CreationFail": { + readonly def: "Failed to create redflag2"; + readonly es: "Error al crear redflag2"; + readonly fr: "Échec de création de redflag2"; + readonly he: "יצירת redflag2 נכשלה"; + readonly ja: "redflag2の作成に失敗しました"; + readonly ko: "redflag2 생성에 실패했습니다"; + readonly ru: "Не удалось создать redflag2"; + readonly zh: "创建 redflag2 失败"; + }; + readonly "moduleMigration.logRemoteTweakUnavailable": { + readonly def: "Could not get remote tweak values"; + readonly es: "No se pudieron obtener los valores de ajuste remoto"; + readonly fr: "Impossible d'obtenir les valeurs d'ajustement distantes"; + readonly he: "לא ניתן לקבל ערכי כיוונון מרוחקים"; + readonly ja: "リモートの調整値を取得できませんでした"; + readonly ko: "원격 조정 값을 가져올 수 없습니다"; + readonly ru: "Не удалось получить удалённые настройки"; + readonly zh: "无法获取远程调整值"; + }; + readonly "moduleMigration.logSetupCancelled": { + readonly def: "The setup has been cancelled, Self-hosted LiveSync waiting for your setup!"; + readonly es: "La configuración ha sido cancelada, ¡Self-hosted LiveSync está esperando tu configuración!"; + readonly fr: "La configuration a été annulée, Self-hosted LiveSync attend votre configuration !"; + readonly he: "ההגדרה בוטלה, Self-hosted LiveSync ממתין להגדרתך!"; + readonly ja: "セットアップがキャンセルされました。Self-hosted LiveSyncはセットアップを待っています!"; + readonly ko: "설정이 취소되었습니다. Self-hosted LiveSync가 설정을 기다리고 있습니다!"; + readonly ru: "Настройка отменена, Self-hosted LiveSync ожидает вашей настройки!"; + readonly zh: "设置已取消,Self-hosted LiveSync 正在等待您的设置!"; + }; + readonly "moduleMigration.msgFetchRemoteAgain": { + readonly def: "As you may already know, the self-hosted LiveSync has changed its default behaviour and database structure.\n\nAnd thankfully, with your time and efforts, the remote database appears to have already been migrated. Congratulations!\n\nHowever, we need a bit more. The configuration of this device is not compatible with the remote database. We will need to fetch the remote database again. Should we fetch from the remote again now?\n\n___Note: We cannot synchronise until the configuration has been changed and the database has been fetched again.___\n___Note2: The chunks are completely immutable, we can fetch only the metadata and difference.___"; + readonly es: "Como ya sabrás, Self-hosted LiveSync ha cambiado su comportamiento predeterminado y la estructura de la base de datos.\n\nAfortunadamente, con tu tiempo y esfuerzo, la base de datos remota parece haber sido ya migrada. ¡Felicidades!\n\nSin embargo, necesitamos un poco más. La configuración de este dispositivo no es compatible con la base de datos remota. Necesitaremos volver a obtener la base de datos remota. ¿Debemos obtenerla nuevamente ahora?\n\n___Nota: No podemos sincronizar hasta que la configuración haya sido cambiada y la base de datos haya sido obtenida nuevamente.___\n___Nota2: Los fragmentos son completamente inmutables, solo podemos obtener los metadatos y diferencias.___"; + readonly fr: "Comme vous le savez peut-être déjà, Self-hosted LiveSync a modifié son comportement par défaut et la structure de sa base de données.\n\nEt, grâce à votre temps et vos efforts, la base distante semble déjà avoir été migrée. Félicitations !\n\nCependant, il faut encore un peu plus. La configuration de cet appareil n'est pas compatible avec la base distante. Nous devrons récupérer à nouveau la base distante. Devons-nous récupérer depuis le distant maintenant ?\n\n___Note : Nous ne pouvons pas synchroniser tant que la configuration n'a pas été modifiée et que la base n'a pas été récupérée à nouveau.___\n___Note 2 : Les fragments sont complètement immuables, nous ne pouvons récupérer que les métadonnées et les différences.___"; + readonly he: "כפי שייתכן שכבר ידוע לך, Self-hosted LiveSync שינה את התנהגות ברירת המחדל ומבנה מסד הנתונים.\n\nובזכות זמנך ומאמציך, מסד הנתונים המרוחד נראה כבר הוגר. ברכות!\n\nעם זאת, נדרש עוד קצת. תצורת מכשיר זה אינה תואמת למסד הנתונים המרוחד. נצטרך למשוך את מסד הנתונים המרוחד שוב. האם למשוך מהשרת המרוחד עכשיו?\n\n___הערה: לא ניתן לסנכרן עד שהתצורה תשתנה ומסד הנתונים יימשך שוב.___\n___הערה 2: הנתחים הם בלתי-ניתנים לשינוי לחלוטין, ניתן למשוך רק את המטה-נתונים וההפרש.___"; + readonly ja: "ご存知のとおり、self-hosted LiveSyncはデフォルトの動作とデータベース構造を変更しました。\n\nご協力のおかげで、リモートデータベースはすでに移行されているようです。おめでとうございます!\n\nしかし、もう少し必要です。このデバイスの設定はリモートデータベースと互換性がありません。リモートデータベースを再度フェッチする必要があります。今すぐリモートから再フェッチしますか?\n\n___注意: 設定が変更され、データベースが再フェッチされるまで同期できません。___\n___注意2: チャンクは完全に不変なので、メタデータと差分のみフェッチできます。___"; + readonly ko: "이미 알고 계시겠지만, Self-hosted LiveSync의 기본 동작 방식과 데이터베이스 구조가 변경되었습니다.\n\n다행히도 여러분의 노력 덕분에 원격 데이터베이스는 이미 성공적으로 데이터 구조 전환이 완료된 것으로 보입니다. 축하드립니다!\n\n하지만 아직 일부 추가 작업이 필요합니다. 이 기기의 설정이 원격 데이터베이스와 호환되지 않으므로, 원격 데이터를 다시 가져와야 합니다. 지금 원격 데이터베이스를 다시 가져오시겠습니까?\n\n___참고: 설정이 변경되고 데이터베이스를 다시 불러오기 전까지는 동기화가 불가능합니다.___\n___참고2: 청크는 변경이 불가능한 구조이므로, 메타데이터와 차이점만 가져올 수 있습니다.___"; + readonly ru: "Удалённая база данных, похоже, уже была мигрирована. Конфигурация этого устройства несовместима."; + readonly zh: "您可能已经知道,Self-hosted LiveSync 更改了其默认行为和数据库结构。\n\n值得庆幸的是,在您的时间和努力下,远程数据库似乎已经迁移完成。恭喜!\n\n但是,我们还需要一点点操作。此设备的配置与远程数据库不兼容。我们需要再次从远程数据库获取。我们现在应该再次从远程获取吗?\n\n___注意:在更改配置并再次获取数据库之前,我们无法进行同步。___\n___注意2:chunks 是完全不可变的,我们只能获取元数据和差异"; + }; + readonly "moduleMigration.msgInitialSetup": { + readonly def: "Your device has **not been set up yet**. Let me guide you through the setup process.\n\nPlease keep in mind that every dialogue content can be copied to the clipboard. If you need to refer to it later, you can paste it into a note in Obsidian. You can also translate it into your language using a translation tool.\n\nFirst, do you have **Setup URI**?\n\nNote: If you do not know what it is, please refer to the [documentation](${URI_DOC})."; + readonly es: "Tu dispositivo **aún no ha sido configurado**. Permíteme guiarte a través del proceso de configuración.\n\nTen en cuenta que todo el contenido del diálogo se puede copiar al portapapeles. Si necesitas consultarlo más tarde, puedes pegarlo en una nota en Obsidian. También puedes traducirlo a tu idioma utilizando una herramienta de traducción.\n\nPrimero, ¿tienes **URI de configuración**?\n\nNota: Si no sabes qué es, consulta la [documentación](${URI_DOC})."; + readonly fr: "Votre appareil n'a **pas encore été configuré**. Laissez-moi vous guider dans le processus de configuration.\n\nVeuillez noter que chaque contenu de boîte de dialogue peut être copié dans le presse-papiers. Si vous souhaitez vous y référer plus tard, vous pouvez le coller dans une note d'Obsidian. Vous pouvez également le traduire dans votre langue via un outil de traduction.\n\nTout d'abord, disposez-vous d'une **URI de configuration** ?\n\nNote : Si vous ne savez pas ce que c'est, consultez la [documentation](${URI_DOC})."; + readonly he: "המכשיר שלך **טרם הוגדר**. אנחנו כאן לעזור לך בתהליך ההגדרה.\n\nשים לב שניתן להעתיק את תוכן כל דיאלוג ללוח. אם צריך לחזור אליו מאוחר יותר, ניתן להדביק אותו כפתק ב-Obsidian. ניתן גם לתרגם לשפתך בעזרת כלי תרגום.\n\nראשית, האם יש לך **Setup URI**?\n\nהערה: אם אינך יודע מהו, אנא עיין ב[תיעוד](${URI_DOC})."; + readonly ja: "このデバイスは**まだセットアップされていません**。セットアッププロセスをご案内します。\n\nすべてのダイアログの内容はクリップボードにコピーできます。後で参照する必要があれば、Obsidianのノートに貼り付けてください。翻訳ツールを使ってお使いの言語に翻訳することもできます。\n\nまず、**セットアップURI**をお持ちですか?\n\n注意: それが何か分からない場合は、[documentation](${URI_DOC})を参照してください。"; + readonly ko: "이 기기는 **아직 초기 설정이 완료되지 않았습니다**. 지금부터 설정 과정을 안내해 드리겠습니다.\n\n모든 대화 내용은 클립보드에 복사할 수 있습니다. 나중에 참고하려면 Obsidian 노트에 붙여넣거나 번역 도구를 활용해 번역하셔도 됩니다.\n\n먼저, **Setup URI**를 가지고 계신가요?\n\n참고: Setup URI가 무엇인지 잘 모르시겠다면 [문서](${URI_DOC})를 참고해 주세요."; + readonly ru: "Ваше устройство ещё не настроено. У вас есть Setup URI?"; + readonly zh: "您的设备**尚未设置**。让我引导您完成设置过程。\n\n请记住,每个对话框内容都可以复制到剪贴板。如果以后需要参考,可以将其粘贴到 Obsidian 的笔记中。您也可以使用翻译工具将其翻译成您的语言。\n\n首先,您有**设置 URI** 吗?\n\n注意:如果您不知道这是什么,请参阅[文档](${URI_DOC})"; + }; + readonly "moduleMigration.msgRecommendSetupUri": { + readonly def: "We strongly recommend that you generate a set-up URI and use it.\nIf you do not have knowledge about it, please refer to the [documentation](${URI_DOC}) (Sorry again, but it is important).\n\nHow do you want to set it up manually?"; + readonly es: "Te recomendamos encarecidamente que generes una URI de configuración y la utilices.\nSi no tienes conocimientos al respecto, consulta la [documentación](${URI_DOC}) (Lo siento de nuevo, pero es importante).\n\n¿Cómo quieres configurarlo manualmente?"; + readonly fr: "Nous recommandons vivement de générer une URI de configuration et de l'utiliser.\nSi vous ne connaissez pas, veuillez consulter la [documentation](${URI_DOC}) (Désolé encore, mais c'est important).\n\nComment souhaitez-vous effectuer la configuration manuellement ?"; + readonly he: "אנו ממליצים בחום לייצר Setup URI ולהשתמש בו.\nאם אין לך ידע בנושא, אנא עיין ב[תיעוד](${URI_DOC}) (מתנצלים שוב, אך זה חשוב).\n\nכיצד ברצונך להגדיר ידנית?"; + readonly ja: "セットアップURIを生成して使用することを強くお勧めします。\nこれについて知識がない場合は、[documentation](${URI_DOC})を参照してください(重要です)。\n\n手動でセットアップしますか?"; + readonly ko: "Setup URI를 생성해 사용하는 것을 강력히 권장합니다.\nSetup URI가 무엇인지 잘 모르시겠다면 [문서](${URI_DOC})를 참고해 주세요. 중요한 내용이니 꼭 확인하시기 바랍니다.\n\n직접 수동 설정을 진행하시겠습니까?"; + readonly ru: "Мы рекомендуем сгенерировать Setup URI."; + readonly zh: "我们强烈建议您生成一个设置 URI 并使用它。\n如果您对此不了解,请参阅[文档](${URI_DOC})(再次抱歉,但这很重要)。\n\n您想如何手动设置?"; + }; + readonly "moduleMigration.msgSinceV02321": { + readonly def: "Since v0.23.21, the self-hosted LiveSync has changed the default behaviour and database structure. The following changes have been made:\n\n1. **Case sensitivity of filenames**\n The handling of filenames is now case-insensitive. This is a beneficial change for most platforms, other than Linux and iOS, which do not manage filename case sensitivity effectively.\n (On These, a warning will be displayed for files with the same name but different cases).\n\n2. **Revision handling of the chunks**\n Chunks are immutable, which allows their revisions to be fixed. This change will enhance the performance of file saving.\n\n___However, to enable either of these changes, both remote and local databases need to be rebuilt. This process takes a few minutes, and we recommend doing it when you have ample time.___\n\n- If you wish to maintain the previous behaviour, you can skip this process by using `${KEEP}`.\n- If you do not have enough time, please choose `${DISMISS}`. You will be prompted again later.\n- If you have rebuilt the database on another device, please select `${DISMISS}` and try synchronizing again. Since a difference has been detected, you will be prompted again."; + readonly es: "Desde la versión v0.23.21, Self-hosted LiveSync ha cambiado el comportamiento predeterminado y la estructura de la base de datos. Se han realizado los siguientes cambios:\n\n1. **Sensibilidad a mayúsculas de los nombres de archivo**\n El manejo de los nombres de archivo ahora no distingue entre mayúsculas y minúsculas. Este cambio es beneficioso para la mayoría de las plataformas, excepto Linux y iOS, que no gestionan efectivamente la sensibilidad a mayúsculas de los nombres de archivo.\n (En estos, se mostrará una advertencia para archivos con el mismo nombre pero diferentes mayúsculas).\n\n2. **Manejo de revisiones de los fragmentos**\n Los fragmentos son inmutables, lo que permite que sus revisiones sean fijas. Este cambio mejorará el rendimiento al guardar archivos.\n\n___Sin embargo, para habilitar cualquiera de estos cambios, es necesario reconstruir tanto las bases de datos remota como la local. Este proceso toma unos minutos, y recomendamos hacerlo cuando tengas tiempo suficiente.___\n\n- Si deseas mantener el comportamiento anterior, puedes omitir este proceso usando `${KEEP}`.\n- Si no tienes suficiente tiempo, por favor elige `${DISMISS}`. Se te pedirá nuevamente más tarde.\n- Si has reconstruido la base de datos en otro dispositivo, selecciona `${DISMISS}` e intenta sincronizar nuevamente. Dado que se ha detectado una diferencia, se te solicitará nuevamente."; + readonly fr: "Depuis la v0.23.21, Self-hosted LiveSync a modifié son comportement par défaut et la structure de sa base. Les changements suivants ont été effectués :\n\n1. **Sensibilité à la casse des noms de fichiers**\n La gestion des noms de fichiers est désormais insensible à la casse. C'est un changement bénéfique pour la plupart des plateformes, hormis Linux et iOS, qui ne gèrent pas efficacement la casse des noms de fichiers.\n (Sur celles-ci, un avertissement s'affichera pour les fichiers portant le même nom avec une casse différente).\n\n2. **Gestion des révisions des fragments**\n Les fragments sont immuables, ce qui permet de fixer leurs révisions. Ce changement améliore les performances d'enregistrement des fichiers.\n\n___Cependant, pour activer l'un ou l'autre de ces changements, les bases locale et distante doivent être reconstruites. Ce processus prend quelques minutes, et nous recommandons de le faire quand vous avez le temps.___\n\n- Si vous souhaitez conserver le comportement précédent, vous pouvez ignorer ce processus via `${KEEP}`.\n- Si vous n'avez pas le temps, choisissez `${DISMISS}`. Vous serez invité à nouveau plus tard.\n- Si vous avez reconstruit la base sur un autre appareil, sélectionnez `${DISMISS}` et réessayez la synchronisation. Une différence étant détectée, vous serez invité à nouveau."; + readonly he: "מאז גרסה 0.23.21, Self-hosted LiveSync שינה את התנהגות ברירת המחדל ומבנה מסד הנתונים. השינויים הבאים בוצעו:\n\n1. **תלות רישיות בשמות קבצים**\n הטיפול בשמות קבצים הוא כעת ללא תלות רישיות. זהו שינוי מועיל לרוב הפלטפורמות,\n פרט ל-Linux ו-iOS שאינן מנהלות תלות רישיות בקבצים ביעילות.\n (בפלטפורמות אלה, תוצג אזהרה עבור קבצים עם אותו שם אך רישיות שונה).\n\n2. **טיפול בגרסאות של נתחים**\n נתחים הם בלתי-ניתנים לשינוי, מה שמאפשר גרסאות קבועות. שינוי זה ישפר את\n ביצועי שמירת הקבצים.\n\n___עם זאת, כדי להפעיל אחד מהשינויים הללו, יש לבנות מחדש גם את מסד הנתונים המרוחד וגם את המקומי. תהליך זה לוקח כמה דקות, ואנו ממליצים לעשות זאת כשיש לך זמן פנוי.___\n\n- אם ברצונך לשמור את ההתנהגות הקודמת, ניתן לדלג על תהליך זה באמצעות `${KEEP}`.\n- אם אין לך מספיק זמן, אנא בחר `${DISMISS}`. תקבל תזכורת בהמשך.\n- אם בנית מחדש את מסד הנתונים במכשיר אחר, אנא בחר `${DISMISS}` ונסה לסנכרן שוב. מאחר שזוהה הפרש, תקבל תזכורת שוב."; + readonly ja: "v0.23.21以降、self-hosted LiveSyncはデフォルトの動作とデータベース構造を変更しました。以下の変更が行われました:\n\n1. **ファイル名の大文字小文字の区別**\n ファイル名の処理が大文字小文字を区別しなくなりました。これは、ファイル名の大文字小文字を効果的に管理しないLinuxとiOS以外のほとんどのプラットフォームにとって有益な変更です。\n (これらの環境では、同じ名前で大文字小文字が異なるファイルに対して警告が表示されます)。\n\n2. **チャンクのリビジョン処理**\n チャンクは不変であり、リビジョンを固定できます。この変更により、ファイル保存のパフォーマンスが向上します。\n\n___しかし、これらの変更を有効にするには、リモートとローカルの両方のデータベースを再構築する必要があります。このプロセスは数分かかります。時間に余裕があるときに行うことをお勧めします。___\n\n- 以前の動作を維持したい場合は、`${KEEP}`を使用してこのプロセスをスキップできます。\n- 時間がない場合は、`${DISMISS}`を選択してください。後で再度確認されます。\n- 別のデバイスでデータベースを再構築した場合は、`${DISMISS}`を選択して再度同期してみてください。差異が検出されたため、再度確認されます。"; + readonly ko: "v0.23.21부터 Self-hosted LiveSync의 기본 동작 방식과 데이터베이스 구조가 변경되었습니다. 주요 변경사항은 다음과 같습니다:\n\n1. **파일명 대소문자 구분 처리**\n 이제 파일명은 대소문자를 구분하지 않고 처리됩니다. 이는 파일명 구분을 제대로 지원하지 않는 Linux 및 iOS를 제외한 대부분의 플랫폼에서 유리한 변화입니다.\n (Linux나 iOS에서는 대소문자만 다른 파일이 존재할 경우 경고가 표시됩니다)\n\n2. **청크 리비전 관리 방식 개선**\n 청크는 변경 불가능한(immutable) 구조로 고정되며, 이를 통해 리비전 처리가 안정화되고 파일 저장 성능이 향상됩니다.\n\n___단, 위 기능을 활성화하려면 원격 및 로컬 데이터베이스를 모두 재구성해야 합니다. 이 과정은 수 분이 소요되므로 여유가 있을 때 실행하시는 것을 권장합니다.___\n\n- 기존 방식대로 유지하려면 `${KEEP}`을 선택해 이 과정을 건너뛸 수 있습니다.\n- 시간이 부족하다면 `${DISMISS}`를 눌러주시면 나중에 다시 안내드리겠습니다.\n- 이미 다른 기기에서 데이터베이스를 재구성하셨다면 `${DISMISS}`를 선택한 뒤 다시 동기화해 보세요. 차이점이 감지되면 다시 안내드리겠습니다."; + readonly ru: "Начиная с v0.23.21, self-hosted LiveSync изменил поведение и структуру базы данных."; + readonly zh: "自 v0.23.21 起,Self-hosted LiveSync 更改了默认行为和数据库结构。进行了以下更改:\n\n1. **文件名的区分大小写** \n现在处理文件名时不区分大小写。这对于大多数平台来说是一个有益的更改,除了 Linux 和 iOS,它们不能有效地管理文件名的大小写敏感性。\n(在这些平台上,对于名称相同但大小写不同的文件将显示警告)。\n\n2. **chunks 的版本处理** \nchunks 是不可变的,这使得它们的版本可以固定。此更改将提高文件保存的性能。\n\n___然而,要启用这些更改中的任何一个,都需要重建远程和本地数据库。这个过程需要几分钟,我们建议您在有充足时间时进行。___\n\n- 如果您希望保持以前的行为,可以使用 `${KEEP}` 跳过此过程。\n- 如果您没有足够的时间,请选择 `${DISMISS}`。稍后会再次提示您。\n- 如果您已在另一台设备上重建了数据库,请选择 `${DISMISS}` 并尝试再次同步。由于检测到差异,系统会再次提示您"; + }; + readonly "moduleMigration.optionAdjustRemote": { + readonly def: "Adjust to remote"; + readonly es: "Ajustar al remoto"; + readonly fr: "Ajuster au distant"; + readonly he: "התאם לשרת המרוחד"; + readonly ja: "リモートに合わせる"; + readonly ko: "원격에 맞추기"; + readonly ru: "Настроить под удалённую"; + readonly zh: "调整到远程设置"; + }; + readonly "moduleMigration.optionDecideLater": { + readonly def: "Decide it later"; + readonly es: "Decidirlo más tarde"; + readonly fr: "Décider plus tard"; + readonly he: "החלט מאוחר יותר"; + readonly ja: "後で決める"; + readonly ko: "나중에 결정하기"; + readonly ru: "Решить позже"; + readonly zh: "稍后决定"; + }; + readonly "moduleMigration.optionEnableBoth": { + readonly def: "Enable both"; + readonly es: "Habilitar ambos"; + readonly fr: "Activer les deux"; + readonly he: "הפעל את שניהם"; + readonly ja: "両方を有効にする"; + readonly ko: "둘 다 활성화"; + readonly ru: "Включить оба"; + readonly zh: "启用两者"; + }; + readonly "moduleMigration.optionEnableFilenameCaseInsensitive": { + readonly def: "Enable only #1"; + readonly es: "Habilitar solo #1"; + readonly fr: "Activer seulement #1"; + readonly he: "הפעל רק #1"; + readonly ja: "#1のみ有効にする"; + readonly ko: "#1만 활성화"; + readonly ru: "Включить только #1"; + readonly zh: "仅启用 #1"; + }; + readonly "moduleMigration.optionEnableFixedRevisionForChunks": { + readonly def: "Enable only #2"; + readonly es: "Habilitar solo #2"; + readonly fr: "Activer seulement #2"; + readonly he: "הפעל רק #2"; + readonly ja: "#2のみ有効にする"; + readonly ko: "#2만 활성화"; + readonly ru: "Включить только #2"; + readonly zh: "仅启用 #2"; + }; + readonly "moduleMigration.optionHaveSetupUri": { + readonly def: "Yes, I have"; + readonly es: "Sí, tengo"; + readonly fr: "Oui, j'en ai une"; + readonly he: "כן, יש לי"; + readonly ja: "はい、持っています"; + readonly ko: "예, 있습니다"; + readonly ru: "Да, есть"; + readonly zh: "是的,我有"; + }; + readonly "moduleMigration.optionKeepPreviousBehaviour": { + readonly def: "Keep previous behaviour"; + readonly es: "Mantener comportamiento anterior"; + readonly fr: "Conserver le comportement précédent"; + readonly he: "שמור על התנהגות קודמת"; + readonly ja: "以前の動作を維持"; + readonly ko: "이전 동작 유지"; + readonly ru: "Сохранить предыдущее поведение"; + readonly zh: "保持以前的行为"; + }; + readonly "moduleMigration.optionManualSetup": { + readonly def: "Set it up all manually"; + readonly es: "Configurarlo todo manualmente"; + readonly fr: "Tout configurer manuellement"; + readonly he: "הגדר הכל ידנית"; + readonly ja: "すべて手動でセットアップ"; + readonly ko: "모든 것을 수동으로 설정"; + readonly ru: "Настроить всё вручную"; + readonly zh: "全部手动设置"; + }; + readonly "moduleMigration.optionNoAskAgain": { + readonly def: "No, please ask again"; + readonly es: "No, por favor pregúntame de nuevo"; + readonly fr: "Non, demandez à nouveau"; + readonly he: "לא, אנא שאל שוב"; + readonly ja: "いいえ、後で確認する"; + readonly ko: "아니요 (나중에 다시 물어보기)"; + readonly ru: "Нет, спросить снова"; + readonly zh: "不,请稍后再次询问"; + }; + readonly "moduleMigration.optionNoSetupUri": { + readonly def: "No, I do not have"; + readonly fr: "Non, je n'en ai pas"; + readonly he: "לא, אין לי"; + readonly ja: "いいえ、持っていません"; + readonly ko: "아니요, 없습니다"; + readonly ru: "Нет, нет"; + readonly zh: "不,我没有"; + }; + readonly "moduleMigration.optionRemindNextLaunch": { + readonly def: "Remind me at the next launch"; + readonly fr: "Me rappeler au prochain lancement"; + readonly he: "הזכר לי בהפעלה הבאה"; + readonly ja: "次回起動時にリマインド"; + readonly ko: "다음 시작 시 알림"; + readonly ru: "Напомнить при следующем запуске"; + readonly zh: "下次启动时提醒我"; + }; + readonly "moduleMigration.optionSetupViaP2P": { + readonly def: "Use P2P Sync to set up"; + readonly fr: "Utiliser Sync P2P pour configurer"; + readonly he: "השתמש ב-%{short_p2p_sync} להגדרה"; + readonly ja: "P2P Sync (試験機能)を使ってセットアップ"; + readonly ko: "P2P 동기화 (실험 기능)를 사용하여 설정"; + readonly ru: "Использовать short_p2p_sync для настройки"; + readonly zh: "Use P2P同步(实验性) to set up"; + }; + readonly "moduleMigration.optionSetupWizard": { + readonly def: "Take me into the setup wizard"; + readonly fr: "Ouvrir l'assistant de configuration"; + readonly he: "קח אותי לאשף ההגדרה"; + readonly ja: "セットアップウィザードへ"; + readonly ko: "설정 마법사로 안내"; + readonly ru: "Перейти в мастер настройки"; + readonly zh: "带我进入设置向导"; + }; + readonly "moduleMigration.optionYesFetchAgain": { + readonly def: "Yes, fetch again"; + readonly fr: "Oui, récupérer à nouveau"; + readonly he: "כן, משוך שוב"; + readonly ja: "はい、再フェッチする"; + readonly ko: "예 (다시 가져오기)"; + readonly ru: "Да, загрузить снова"; + readonly zh: "是的,再次获取"; + }; + readonly "moduleMigration.titleCaseSensitivity": { + readonly def: "Case Sensitivity"; + readonly fr: "Sensibilité à la casse"; + readonly he: "תלות רישיות"; + readonly ja: "大文字小文字の区別"; + readonly ko: "대소문자 구분"; + readonly ru: "Чувствительность к регистру"; + readonly zh: "大小写敏感性"; + }; + readonly "moduleMigration.titleRecommendSetupUri": { + readonly def: "Recommendation to use Setup URI"; + readonly fr: "Recommandation d'utilisation de l'URI de configuration"; + readonly he: "המלצה לשימוש ב-Setup URI"; + readonly ja: "セットアップURIの使用を推奨"; + readonly ko: "Setup URI 사용 권장"; + readonly ru: "Рекомендация использовать Setup URI"; + readonly zh: "推荐使用设置 URI"; + }; + readonly "moduleMigration.titleWelcome": { + readonly def: "Welcome to Self-hosted LiveSync"; + readonly fr: "Bienvenue dans Self-hosted LiveSync"; + readonly he: "ברוך הבא ל-Self-hosted LiveSync"; + readonly ja: "Self-hosted LiveSyncへようこそ"; + readonly ko: "Self-hosted LiveSync에 오신 것을 환영합니다"; + readonly ru: "Добро пожаловать в Self-hosted LiveSync"; + readonly zh: "欢迎使用 Self-hosted LiveSync"; + }; + readonly "moduleObsidianMenu.replicate": { + readonly def: "Replicate"; + readonly es: "Replicar"; + readonly fr: "Répliquer"; + readonly he: "שכפל"; + readonly ja: "レプリケート"; + readonly ko: "복제"; + readonly ru: "Реплицировать"; + readonly zh: "复制"; + }; + readonly "More actions": { + readonly def: "More actions"; + readonly es: "Más acciones"; + readonly ja: "その他の操作"; + readonly ko: "추가 작업"; + readonly ru: "Другие действия"; + readonly zh: "更多操作"; + readonly "zh-tw": "更多操作"; + }; + readonly "Move remotely deleted files to the trash, instead of deleting.": { + readonly def: "Move remotely deleted files to the trash, instead of deleting."; + readonly es: "Mover archivos borrados remotos a papelera en lugar de eliminarlos"; + readonly fr: "Déplacer les fichiers supprimés à distance vers la corbeille, au lieu de les supprimer."; + readonly he: "העבר קבצים שנמחקו מרחוק לאשפה, במקום למחוק."; + readonly ja: "リモートで削除されたファイルを削除せずにゴミ箱に移動する。"; + readonly ko: "원격에서 삭제된 파일을 삭제하는 대신 휴지통으로 이동합니다."; + readonly ru: "Перемещать удалённые на удалённом сервере файлы в корзину вместо удаления."; + readonly zh: "将远程删除的文件移至回收站,而不是直接删除"; + }; + readonly "Network warning style": { + readonly def: "Network warning style"; + readonly es: "Estilo de advertencia de red"; + readonly ja: "ネットワーク警告の表示方式"; + readonly ko: "네트워크 경고 표시 방식"; + readonly ru: "Стиль сетевого предупреждения"; + readonly zh: "网络警告样式"; + readonly "zh-tw": "網路警告樣式"; + }; + readonly "New Remote": { + readonly def: "New Remote"; + readonly es: "Nuevo remoto"; + readonly ja: "新しいリモート"; + readonly ko: "새 원격"; + readonly ru: "Новое удалённое хранилище"; + readonly zh: "新建远端"; + readonly "zh-tw": "新增遠端"; + }; + readonly "No connected device information found. Cancelling Garbage Collection.": { + readonly def: "No connected device information found. Cancelling Garbage Collection."; + readonly ja: "接続済みデバイスの情報が見つかりませんでした。Garbage Collection をキャンセルします。"; + readonly ko: "연결된 기기 정보를 찾을 수 없습니다. Garbage Collection을 취소합니다."; + readonly ru: "Не найдена информация о подключённых устройствах. Garbage Collection отменяется."; + readonly zh: "未找到已连接设备的信息。正在取消垃圾回收。"; + readonly "zh-tw": "找不到已連線裝置的資訊。正在取消垃圾回收。"; + }; + readonly "No limit configured": { + readonly def: "No limit configured"; + readonly es: "Sin límite configurado"; + readonly ja: "制限は設定されていません"; + readonly ko: "제한이 설정되지 않음"; + readonly ru: "Лимит не задан"; + readonly zh: "未配置限制"; + readonly "zh-tw": "尚未設定限制"; + }; + readonly "No, please take me back": { + readonly def: "No, please take me back"; + readonly es: "No, volver atrás"; + readonly ja: "いいえ、前に戻ります"; + readonly ko: "아니요, 이전으로 돌아가겠습니다"; + readonly ru: "Нет, верните меня назад"; + readonly zh: "不,返回上一步"; + readonly "zh-tw": "不,返回上一步"; + }; + readonly "Node ID": { + readonly def: "Node ID"; + readonly ja: "ノード ID"; + readonly ko: "노드 ID"; + readonly ru: "ID узла"; + readonly zh: "节点 ID"; + readonly "zh-tw": "節點 ID"; + }; + readonly "Node Information Missing": { + readonly def: "Node Information Missing"; + readonly ja: "ノード情報がありません"; + readonly ko: "노드 정보 누락"; + readonly ru: "Отсутствует информация об узле"; + readonly zh: "节点信息缺失"; + readonly "zh-tw": "節點資訊缺失"; + }; + readonly "Non-Synchronising files": { + readonly def: "Non-Synchronising files"; + readonly es: "Archivos no sincronizados"; + readonly ja: "同期しないファイル"; + readonly ko: "동기화하지 않는 파일"; + readonly ru: "Несинхронизируемые файлы"; + readonly zh: "不同步的文件"; + readonly "zh-tw": "不同步的檔案"; + }; + readonly "Normal Files": { + readonly def: "Normal Files"; + readonly es: "Archivos normales"; + readonly ja: "通常ファイル"; + readonly ko: "일반 파일"; + readonly ru: "Обычные файлы"; + readonly zh: "普通文件"; + readonly "zh-tw": "一般檔案"; + }; + readonly 'Not all messages have been translated. And, please revert to "Default" when reporting errors.': { + readonly def: "Not all messages have been translated. And, please revert to \"Default\" when reporting errors."; + readonly es: "No todos los mensajes están traducidos. Por favor, vuelva a \"Predeterminado\" al reportar errores."; + readonly fr: "Tous les messages n'ont pas été traduits. Et veuillez revenir à « Par défaut » lorsque vous signalez des erreurs."; + readonly he: "לא כל ההודעות תורגמו. בנוסף, אנא חזור ל\"ברירת מחדל\" בעת דיווח על שגיאות."; + readonly ja: "すべてのメッセージが翻訳されているわけではありません。また、Issue報告の際にはいったん\"Default\"に戻してください"; + readonly ko: "모든 메시지가 번역되지 않았습니다. 오류 신고 시 \"기본값\"으로 되돌려 주세요."; + readonly ru: "Не все сообщения переведены. И, пожалуйста, вернитесь к «По умолчанию» при сообщении об ошибках."; + readonly zh: "并非所有消息都已翻译。请在报告错误时恢复为\"默认\""; + }; + readonly "Notify all setting files": { + readonly def: "Notify all setting files"; + readonly es: "Notificar todos los archivos de configuración"; + readonly fr: "Notifier tous les fichiers de paramètres"; + readonly he: "הודע על כל קבצי ההגדרות"; + readonly ja: "すべての設定を通知"; + readonly ko: "모든 설정 파일 알림"; + readonly ru: "Уведомлять обо всех файлах настроек"; + readonly zh: "通知所有设置文件"; + }; + readonly "Notify customized": { + readonly def: "Notify customized"; + readonly es: "Notificar personalizaciones"; + readonly fr: "Notifier les personnalisations"; + readonly he: "הודע על התאמות אישיות"; + readonly ja: "カスタマイズが行われたら通知する"; + readonly ko: "사용자 설정 알림"; + readonly ru: "Уведомлять о настройках"; + readonly zh: "通知自定义设置"; + }; + readonly "Notify when other device has newly customized.": { + readonly def: "Notify when other device has newly customized."; + readonly es: "Notificar cuando otro dispositivo personalice"; + readonly fr: "Notifier lorsqu'un autre appareil a une nouvelle personnalisation."; + readonly he: "הודע כאשר מכשיר אחר הוסיף התאמה אישית חדשה."; + readonly ja: "別の端末がカスタマイズを行なったら通知する"; + readonly ko: "다른 기기에서 새로운 사용자 설정이 있을 때 알림을 받습니다."; + readonly ru: "Уведомлять, когда другое устройство изменило настройки."; + readonly zh: "当其他设备有新的自定义设置时通知 "; + }; + readonly "Notify when the estimated remote storage size exceeds on start up": { + readonly def: "Notify when the estimated remote storage size exceeds on start up"; + readonly es: "Notificar cuando el tamaño estimado del almacenamiento remoto exceda al iniciar"; + readonly fr: "Notifier quand la taille estimée du stockage distant est dépassée au démarrage"; + readonly he: "הודע כשגודל האחסון המרוחד המשוער עולה על הסף בעת הפעלה"; + readonly ja: "起動時に予想リモートストレージサイズを超えたら通知"; + readonly ko: "시작 시 예상 원격 스토리지 크기가 초과되면 알림"; + readonly ru: "Уведомлять, когда оценочный размер удалённого хранилища превышает при запуске"; + readonly zh: "启动时当估计的远程存储大小超出时通知"; + }; + readonly "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": { + readonly def: "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time."; + readonly es: "Número de lotes a procesar. Default 40, mínimo 2. Controla documentos en memoria"; + readonly fr: "Nombre de lots à traiter à la fois. Par défaut 40. Minimum 2. Ceci, avec la taille de lot, contrôle le nombre de documents conservés en mémoire à la fois."; + readonly he: "מספר האצוות לעיבוד בכל פעם. ברירת מחדל 40, מינימום 2. יחד עם גודל האצווה קובע כמה מסמכים נשמרים בזיכרון בו-זמנית."; + readonly ja: "1度に処理するバッチの数。デフォルトは40、最小は2。この数値は、どれだけの容量の書類がメモリに保存されるかも定義します。"; + readonly ko: "한 번에 처리할 일괄 처리 수입니다. 기본값은 40입니다. 최소값은 2입니다. 이는 일괄 크기와 함께 메모리에 보관되는 문서 수를 제어합니다."; + readonly ru: "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time."; + readonly zh: "一次处理的批量数量。默认为 40。最小为 2。此设置与批量大小一起控制一次在内存中保留多少文档"; + }; + readonly "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": { + readonly def: "Number of changes to sync at a time. Defaults to 50. Minimum is 2."; + readonly es: "Número de cambios a sincronizar simultáneamente. Default 50, mínimo 2"; + readonly fr: "Nombre de modifications à synchroniser à la fois. Par défaut 50. Minimum 2."; + readonly he: "מספר השינויים לסנכרון בכל פעם. ברירת מחדל 50, מינימום 2."; + readonly ja: "一度に同期する変更の数。デフォルトは50、最小は2。"; + readonly ko: "한 번에 동기화할 변경 사항의 수입니다. 기본값은 50입니다. 최소값은 2입니다."; + readonly ru: "Количество изменений для синхронизации за раз. По умолчанию 50. Минимум 2."; + readonly zh: "一次同步的更改数量。默认为 50。最小为 2。"; + }; + readonly "Obsidian version": { + readonly def: "Obsidian version"; + readonly ja: "Obsidian バージョン"; + readonly ko: "Obsidian 버전"; + readonly ru: "Версия Obsidian"; + readonly zh: "Obsidian 版本"; + readonly "zh-tw": "Obsidian 版本"; + }; + readonly "obsidianLiveSyncSettingTab.btnApply": { + readonly def: "Apply"; + readonly es: "Aplicar"; + readonly fr: "Appliquer"; + readonly he: "החל"; + readonly ja: "適用"; + readonly ko: "적용"; + readonly ru: "Применить"; + readonly zh: "应用"; + readonly "zh-tw": "套用"; + }; + readonly "obsidianLiveSyncSettingTab.btnCheck": { + readonly def: "Check"; + readonly es: "Verificar"; + readonly fr: "Vérifier"; + readonly he: "בדוק"; + readonly ja: "確認"; + readonly ko: "확인"; + readonly ru: "Проверить"; + readonly zh: "检查"; + }; + readonly "obsidianLiveSyncSettingTab.btnCopy": { + readonly def: "Copy"; + readonly es: "Copiar"; + readonly fr: "Copier"; + readonly he: "העתק"; + readonly ja: "コピー"; + readonly ko: "복사"; + readonly ru: "Копировать"; + readonly zh: "复制"; + }; + readonly "obsidianLiveSyncSettingTab.btnDisable": { + readonly def: "Disable"; + readonly es: "Desactivar"; + readonly fr: "Désactiver"; + readonly he: "נטרל"; + readonly ja: "無効化"; + readonly ko: "비활성화"; + readonly ru: "Отключить"; + readonly zh: "禁用"; + readonly "zh-tw": "停用"; + }; + readonly "obsidianLiveSyncSettingTab.btnDiscard": { + readonly def: "Discard"; + readonly es: "Descartar"; + readonly fr: "Abandonner"; + readonly he: "ביטול שינויים"; + readonly ja: "破棄"; + readonly ko: "삭제"; + readonly ru: "Отменить"; + readonly zh: "丢弃"; + }; + readonly "obsidianLiveSyncSettingTab.btnEnable": { + readonly def: "Enable"; + readonly es: "Activar"; + readonly fr: "Activer"; + readonly he: "הפעל"; + readonly ja: "有効化"; + readonly ko: "활성화"; + readonly ru: "Включить"; + readonly zh: "启用"; + }; + readonly "obsidianLiveSyncSettingTab.btnFix": { + readonly def: "Fix"; + readonly es: "Corregir"; + readonly fr: "Corriger"; + readonly he: "תקן"; + readonly ja: "修正"; + readonly ko: "수정"; + readonly ru: "Исправить"; + readonly zh: "修复"; + }; + readonly "obsidianLiveSyncSettingTab.btnGotItAndUpdated": { + readonly def: "I got it and updated."; + readonly es: "Lo entendí y actualicé."; + readonly fr: "J'ai compris et mis à jour."; + readonly he: "הבנתי ועדכנתי."; + readonly ja: "理解しました、更新しました。"; + readonly ko: "알겠습니다. 업데이트했습니다."; + readonly ru: "Понял и обновил."; + readonly zh: "我明白了并且已更新"; + }; + readonly "obsidianLiveSyncSettingTab.btnNext": { + readonly def: "Next"; + readonly es: "Siguiente"; + readonly fr: "Suivant"; + readonly he: "הבא"; + readonly ja: "次へ"; + readonly ko: "다음"; + readonly ru: "Далее"; + readonly zh: "下一步"; + readonly "zh-tw": "下一步"; + }; + readonly "obsidianLiveSyncSettingTab.btnStart": { + readonly def: "Start"; + readonly es: "Iniciar"; + readonly fr: "Démarrer"; + readonly he: "התחל"; + readonly ja: "開始"; + readonly ko: "시작"; + readonly ru: "Старт"; + readonly zh: "开始"; + }; + readonly "obsidianLiveSyncSettingTab.btnTest": { + readonly def: "Test"; + readonly es: "Probar"; + readonly fr: "Tester"; + readonly he: "בדוק"; + readonly ja: "テスト"; + readonly ko: "테스트"; + readonly ru: "Тест"; + readonly zh: "测试"; + }; + readonly "obsidianLiveSyncSettingTab.btnUse": { + readonly def: "Use"; + readonly es: "Usar"; + readonly fr: "Utiliser"; + readonly he: "השתמש"; + readonly ja: "使用"; + readonly ko: "사용"; + readonly ru: "Использовать"; + readonly zh: "使用"; + }; + readonly "obsidianLiveSyncSettingTab.buttonFetch": { + readonly def: "Fetch"; + readonly es: "Obtener"; + readonly fr: "Récupérer"; + readonly he: "משוך"; + readonly ja: "フェッチ"; + readonly ko: "가져오기"; + readonly ru: "Загрузить"; + readonly zh: "获取"; + }; + readonly "obsidianLiveSyncSettingTab.buttonNext": { + readonly def: "Next"; + readonly es: "Siguiente"; + readonly fr: "Suivant"; + readonly he: "הבא"; + readonly ja: "次へ"; + readonly ko: "다음"; + readonly ru: "Далее"; + readonly zh: "下一步"; + readonly "zh-tw": "下一步"; + }; + readonly "obsidianLiveSyncSettingTab.defaultLanguage": { + readonly def: "Default"; + readonly es: "Predeterminado"; + readonly fr: "Par défaut"; + readonly he: "ברירת מחדל"; + readonly ja: "デフォルト"; + readonly ko: "기본값"; + readonly ru: "По умолчанию"; + readonly zh: "默认语言"; + readonly "zh-tw": "預設語言"; + }; + readonly "obsidianLiveSyncSettingTab.descConnectSetupURI": { + readonly def: "This is the recommended method to set up Self-hosted LiveSync with a Setup URI."; + readonly es: "Este es el método recomendado para configurar Self-hosted LiveSync con una URI de configuración."; + readonly fr: "Méthode recommandée pour configurer Self-hosted LiveSync avec une URI de configuration."; + readonly he: "זוהי השיטה המומלצת להגדרת Self-hosted LiveSync עם Setup URI."; + readonly ja: "セットアップURIを使用してSelf-hosted LiveSyncをセットアップする推奨方法です。"; + readonly ko: "이것은 Setup URI로 Self-hosted LiveSync를 설정하는 권장 방법입니다."; + readonly ru: "Это рекомендуемый способ настройки Self-hosted LiveSync с помощью Setup URI."; + readonly zh: "这是使用设置 URI 设置 Self-hosted LiveSync 的推荐方法"; + }; + readonly "obsidianLiveSyncSettingTab.descCopySetupURI": { + readonly def: "Perfect for setting up a new device!"; + readonly es: "¡Perfecto para configurar un nuevo dispositivo!"; + readonly fr: "Parfait pour configurer un nouvel appareil !"; + readonly he: "מושלם להגדרת מכשיר חדש!"; + readonly ja: "新しいデバイスのセットアップにおすすめ!"; + readonly ko: "새 기기 설정에 완벽합니다!"; + readonly ru: "Идеально подходит для настройки нового устройства!"; + readonly zh: "非常适合设置新设备!"; + }; + readonly "obsidianLiveSyncSettingTab.descEnableLiveSync": { + readonly def: "Only enable this after configuring either of the above two options or completing all configuration manually."; + readonly es: "Solo habilita esto después de configurar cualquiera de las dos opciones anteriores o completar toda la configuración manualmente."; + readonly fr: "N'activez ceci qu'après avoir configuré l'une des deux options ci-dessus ou terminé toute la configuration manuellement."; + readonly he: "הפעל רק לאחר הגדרת אחת משתי האפשרויות לעיל, או לאחר השלמת כל ההגדרות ידנית."; + readonly ja: "上記の2つのオプションのいずれかを設定するか、すべての設定を手動で完了した後にのみ有効にしてください。"; + readonly ko: "위의 두 옵션 중 하나를 구성하거나 모든 구성을 수동으로 완료한 후에만 활성화하세요."; + readonly ru: "Включайте это только после настройки одного из двух вариантов выше или после полного ручного завершения всей конфигурации."; + readonly zh: "仅在配置了上述两个选项之一或手动完成所有配置后启用此选项"; + }; + readonly "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": { + readonly def: "Fetch necessary settings from already configured remote server."; + readonly es: "Obtener las configuraciones necesarias del servidor remoto ya configurado."; + readonly fr: "Récupérer les paramètres nécessaires depuis un serveur distant déjà configuré."; + readonly he: "משוך הגדרות נדרשות מהשרת המרוחד שהוגדר כבר."; + readonly ja: "既に設定済みのリモートサーバーから必要な設定を取得します。"; + readonly ko: "이미 구성된 원격 서버에서 필요한 설정을 가져옵니다."; + readonly ru: "Получить необходимые настройки с уже настроенного удалённого сервера."; + readonly zh: "从已配置的远程服务器获取必要的设置"; + }; + readonly "obsidianLiveSyncSettingTab.descManualSetup": { + readonly def: "Not recommended, but useful if you don't have a Setup URI"; + readonly es: "No recomendado, pero útil si no tienes una URI de configuración"; + readonly fr: "Non recommandé, mais utile si vous n'avez pas d'URI de configuration"; + readonly he: "לא מומלץ, אך שימושי אם אין לך Setup URI"; + readonly ja: "推奨しませんが、セットアップURIがない場合に便利です"; + readonly ko: "권장하지 않지만 Setup URI가 없는 경우에 유용합니다"; + readonly ru: "Не рекомендуется, но полезно, если у вас нет Setup URI."; + readonly zh: "不推荐,但如果您没有设置 URI 则很有用"; + }; + readonly "obsidianLiveSyncSettingTab.descTestDatabaseConnection": { + readonly def: "Open database connection. If the remote database is not found and you have permission to create a database, the database will be created."; + readonly es: "Abrir conexión a la base de datos. Si no se encuentra la base de datos remota y tienes permiso para crear una base de datos, se creará la base de datos."; + readonly fr: "Ouvrir la connexion à la base de données. Si la base distante est introuvable et que vous avez l'autorisation de créer une base, elle sera créée."; + readonly he: "פתח חיבור למסד נתונים. אם מסד הנתונים המרוחד לא נמצא ויש לך הרשאה ליצור אחד, הוא ייצור."; + readonly ja: "データベース接続を開きます。リモートデータベースが見つからず、データベースを作成する権限がある場合は、データベースが作成されます。"; + readonly ko: "데이터베이스 연결을 엽니다. 원격 데이터베이스를 찾을 수 없고 데이터베이스 생성 권한이 있는 경우, 데이터베이스가 생성됩니다."; + readonly ru: "Открыть подключение к базе данных. Если удалённая база данных не найдена и у вас есть право на её создание, база будет создана."; + readonly zh: "打开数据库连接。如果未找到远程数据库并且您有创建数据库的权限,则将创建数据库"; + }; + readonly "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": { + readonly def: "Checks and fixes any potential issues with the database config."; + readonly es: "Verifica y soluciona cualquier problema potencial con la configuración de la base de datos."; + readonly fr: "Vérifie et corrige les problèmes potentiels de la configuration de la base."; + readonly he: "בודק ומתקן בעיות אפשריות בתצורת מסד הנתונים."; + readonly ja: "データベース設定の潜在的な問題を確認し、修正します。"; + readonly ko: "데이터베이스 구성의 잠재적 문제를 확인하고 수정합니다."; + readonly ru: "Проверяет и исправляет любые потенциальные проблемы в конфигурации базы данных."; + readonly zh: "检查并修复数据库配置中的任何潜在问题"; + }; + readonly "obsidianLiveSyncSettingTab.errAccessForbidden": { + readonly def: "❗ Access forbidden."; + readonly es: "Acceso prohibido."; + readonly fr: "❗ Accès interdit."; + readonly he: "❗ גישה נדחתה."; + readonly ja: "❗ アクセスが禁止されています。"; + readonly ko: "❗ 액세스가 금지되었습니다."; + readonly ru: "❗ Доступ запрещён."; + readonly zh: "❗ 访问被禁止"; + }; + readonly "obsidianLiveSyncSettingTab.errCannotContinueTest": { + readonly def: "We could not continue the test."; + readonly es: "No se pudo continuar con la prueba."; + readonly fr: "Impossible de poursuivre le test."; + readonly he: "לא ניתן להמשיך בבדיקה."; + readonly ja: "テストを続行できませんでした。"; + readonly ko: "테스트를 계속할 수 없습니다."; + readonly ru: "Мы не можем продолжить тест."; + readonly zh: "我们无法继续测试。"; + }; + readonly "obsidianLiveSyncSettingTab.errCorsCredentials": { + readonly def: "❗ cors.credentials is wrong"; + readonly es: "❗ cors.credentials es incorrecto"; + readonly fr: "❗ cors.credentials est incorrect"; + readonly he: "❗ cors.credentials שגוי"; + readonly ja: "❗ cors.credentialsが不正です"; + readonly ko: "❗ cors.credentials가 잘못되었습니다"; + readonly ru: "❗ cors.credentials неверно"; + readonly zh: "❗ cors.credentials 设置错误"; + }; + readonly "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": { + readonly def: "❗ CORS is not allowing credentials"; + readonly es: "CORS no permite credenciales"; + readonly fr: "❗ CORS n'autorise pas les identifiants"; + readonly he: "❗ CORS אינו מאפשר פרטי גישה"; + readonly ja: "❗ CORSが認証情報を許可していません"; + readonly ko: "❗ CORS에서 자격 증명을 허용하지 않습니다"; + readonly ru: "❗ CORS не разрешает учётные данные"; + readonly zh: "❗ CORS 不允许凭据"; + }; + readonly "obsidianLiveSyncSettingTab.errCorsOrigins": { + readonly def: "❗ cors.origins is wrong"; + readonly es: "❗ cors.origins es incorrecto"; + readonly fr: "❗ cors.origins est incorrect"; + readonly he: "❗ cors.origins שגוי"; + readonly ja: "❗ cors.originsが不正です"; + readonly ko: "❗ cors.origins가 잘못되었습니다"; + readonly ru: "❗ cors.origins неверно"; + readonly zh: "❗ cors.origins 设置错误"; + }; + readonly "obsidianLiveSyncSettingTab.errEnableCors": { + readonly def: "❗ httpd.enable_cors is wrong"; + readonly es: "❗ httpd.enable_cors es incorrecto"; + readonly fr: "❗ httpd.enable_cors est incorrect"; + readonly he: "❗ httpd.enable_cors שגוי"; + readonly ja: "❗ httpd.enable_corsが不正です"; + readonly ko: "❗ httpd.enable_cors가 잘못되었습니다"; + readonly ru: "❗ httpd.enable_cors неверно"; + readonly zh: "❗ httpd.enable_cors 设置错误"; + }; + readonly "obsidianLiveSyncSettingTab.errEnableCorsChttpd": { + readonly def: "❗ chttpd.enable_cors is wrong"; + readonly fr: "❗ chttpd.enable_cors est incorrect"; + readonly he: "❗ chttpd.enable_cors שגוי"; + readonly ja: "❗ chttpd.enable_corsが不正です"; + readonly ru: "❗ chttpd.enable_cors неверно"; + readonly zh: "❗ chttpd.enable_cors 设置错误"; + }; + readonly "obsidianLiveSyncSettingTab.errMaxDocumentSize": { + readonly def: "❗ couchdb.max_document_size is low)"; + readonly es: "❗ couchdb.max_document_size es bajo)"; + readonly fr: "❗ couchdb.max_document_size est trop bas)"; + readonly he: "❗ couchdb.max_document_size נמוך)"; + readonly ja: "❗ couchdb.max_document_sizeが低すぎます"; + readonly ko: "❗ couchdb.max_document_size가 낮습니다)"; + readonly ru: "❗ couchdb.max_document_size низкое"; + readonly zh: "❗ couchdb.max_document_size 设置过低)"; + }; + readonly "obsidianLiveSyncSettingTab.errMaxRequestSize": { + readonly def: "❗ chttpd.max_http_request_size is low)"; + readonly es: "❗ chttpd.max_http_request_size es bajo)"; + readonly fr: "❗ chttpd.max_http_request_size est trop bas)"; + readonly he: "❗ chttpd.max_http_request_size נמוך)"; + readonly ja: "❗ chttpd.max_http_request_sizeが低すぎます"; + readonly ko: "❗ chttpd.max_http_request_size가 낮습니다)"; + readonly ru: "❗ chttpd.max_http_request_size низкое"; + readonly zh: "❗ chttpd.max_http_request_size 设置过低)"; + }; + readonly "obsidianLiveSyncSettingTab.errMissingWwwAuth": { + readonly def: "❗ httpd.WWW-Authenticate is missing"; + readonly es: "❗ httpd.WWW-Authenticate falta"; + readonly fr: "❗ httpd.WWW-Authenticate est manquant"; + readonly he: "❗ httpd.WWW-Authenticate חסר"; + readonly ja: "❗ httpd.WWW-Authenticateが不足しています"; + readonly ko: "❗ httpd.WWW-Authenticate가 누락되었습니다"; + readonly ru: "❗ httpd.WWW-Authenticate отсутствует"; + readonly zh: "❗ 缺少 httpd.WWW-Authenticate 设置"; + }; + readonly "obsidianLiveSyncSettingTab.errRequireValidUser": { + readonly def: "❗ chttpd.require_valid_user is wrong."; + readonly es: "❗ chttpd.require_valid_user es incorrecto."; + readonly fr: "❗ chttpd.require_valid_user est incorrect."; + readonly he: "❗ chttpd.require_valid_user שגוי."; + readonly ja: "❗ chttpd.require_valid_userが不正です。"; + readonly ko: "❗ chttpd.require_valid_user가 잘못되었습니다."; + readonly ru: "❗ chttpd.require_valid_user неверно."; + readonly zh: "❗ chttpd.require_valid_user 设置错误"; + }; + readonly "obsidianLiveSyncSettingTab.errRequireValidUserAuth": { + readonly def: "❗ chttpd_auth.require_valid_user is wrong."; + readonly es: "❗ chttpd_auth.require_valid_user es incorrecto."; + readonly fr: "❗ chttpd_auth.require_valid_user est incorrect."; + readonly he: "❗ chttpd_auth.require_valid_user שגוי."; + readonly ja: "❗ chttpd_auth.require_valid_userが不正です。"; + readonly ko: "❗ chttpd_auth.require_valid_user가 잘못되었습니다."; + readonly ru: "❗ chttpd_auth.require_valid_user неверно."; + readonly zh: "❗ chttpd_auth.require_valid_user 设置错误"; + }; + readonly "obsidianLiveSyncSettingTab.labelDisabled": { + readonly def: "⏹️ : Disabled"; + readonly es: "⏹️ : Desactivado"; + readonly fr: "⏹️ : Désactivé"; + readonly he: "⏹️ : מנוטרל"; + readonly ja: "⏹️ : 無効"; + readonly ko: "⏹️ : 비활성화됨"; + readonly ru: "⏹️ : Отключено"; + readonly zh: "⏹️:已禁用"; + readonly "zh-tw": "⏹️ : 已停用"; + }; + readonly "obsidianLiveSyncSettingTab.labelEnabled": { + readonly def: "🔁 : Enabled"; + readonly es: "🔁 : Activado"; + readonly fr: "🔁 : Activé"; + readonly he: "🔁 : מופעל"; + readonly ja: "🔁 : 有効"; + readonly ko: "🔁 : 활성화됨"; + readonly ru: "🔁 : Включено"; + readonly zh: "🔁:已启用"; + readonly "zh-tw": "🔁 : 已啟用"; + }; + readonly "obsidianLiveSyncSettingTab.levelAdvanced": { + readonly def: " (Advanced)"; + readonly es: " (avanzado)"; + readonly fr: " (Avancé)"; + readonly he: " (מתקדם)"; + readonly ja: " (上級)"; + readonly ko: " (고급)"; + readonly ru: " (Расширенные)"; + readonly zh: "(进阶)"; + }; + readonly "obsidianLiveSyncSettingTab.levelEdgeCase": { + readonly def: " (Edge Case)"; + readonly es: " (excepción)"; + readonly fr: " (Cas particulier)"; + readonly he: " (מקרה קצה)"; + readonly ja: " (エッジケース)"; + readonly ko: " (특수 사례)"; + readonly ru: " (Граничные случаи)"; + readonly zh: "(边缘情况)"; + }; + readonly "obsidianLiveSyncSettingTab.levelPowerUser": { + readonly def: " (Power User)"; + readonly es: " (experto)"; + readonly fr: " (Utilisateur avancé)"; + readonly he: " (משתמש מתקדם)"; + readonly ja: " (エキスパート)"; + readonly ko: " (파워 유저)"; + readonly ru: " (Опытный пользователь)"; + readonly zh: "(高级用户)"; + }; + readonly "obsidianLiveSyncSettingTab.linkOpenInBrowser": { + readonly def: "Open in browser"; + readonly es: "Abrir en el navegador"; + readonly fr: "Ouvrir dans le navigateur"; + readonly he: "פתח בדפדפן"; + readonly ja: "ブラウザで開く"; + readonly ko: "브라우저에서 열기"; + readonly ru: "Открыть в браузере"; + readonly zh: "在浏览器中打开"; + }; + readonly "obsidianLiveSyncSettingTab.linkPageTop": { + readonly def: "Page Top"; + readonly es: "Ir arriba"; + readonly fr: "Haut de la page"; + readonly he: "ראש העמוד"; + readonly ja: "ページトップ"; + readonly ko: "페이지 상단"; + readonly ru: "В начало страницы"; + readonly zh: "页面顶部"; + }; + readonly "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": { + readonly def: "Tips and Troubleshooting"; + readonly es: "Consejos y solución de problemas"; + readonly fr: "Conseils et dépannage"; + readonly he: "טיפים ופתרון בעיות"; + readonly ja: "ヒントとトラブルシューティング"; + readonly ko: "팁 및 문제 해결"; + readonly ru: "Советы и устранение неполадок"; + readonly zh: "提示和故障排除"; + }; + readonly "obsidianLiveSyncSettingTab.linkTroubleshooting": { + readonly def: "/docs/troubleshooting.md"; + readonly es: "/docs/es/troubleshooting.md"; + readonly fr: "/docs/troubleshooting.md"; + readonly he: "/docs/troubleshooting.md"; + readonly ja: "/docs/troubleshooting.md"; + readonly ko: "/docs/troubleshooting.md"; + readonly ru: "/docs/troubleshooting.md"; + readonly zh: "/docs/troubleshooting.md"; + }; + readonly "obsidianLiveSyncSettingTab.logCannotUseCloudant": { + readonly def: "This feature cannot be used with IBM Cloudant."; + readonly es: "Esta función no se puede utilizar con IBM Cloudant."; + readonly fr: "Cette fonctionnalité ne peut pas être utilisée avec IBM Cloudant."; + readonly he: "לא ניתן להשתמש בתכונה זו עם IBM Cloudant."; + readonly ja: "この機能はIBM Cloudantでは使用できません。"; + readonly ko: "이 기능은 IBM Cloudant와 함께 사용할 수 없습니다."; + readonly ru: "Эта функция недоступна для IBM Cloudant."; + readonly zh: "此功能不能与 IBM Cloudant 一起使用 "; + }; + readonly "obsidianLiveSyncSettingTab.logCheckingConfigDone": { + readonly def: "Checking configuration done"; + readonly es: "Verificación de configuración completada"; + readonly fr: "Vérification de la configuration terminée"; + readonly he: "בדיקת התצורה הושלמה"; + readonly ja: "設定の確認が完了しました"; + readonly ko: "구성 확인 완료"; + readonly ru: "Проверка конфигурации завершена"; + readonly zh: "配置检查完成"; + }; + readonly "obsidianLiveSyncSettingTab.logCheckingConfigFailed": { + readonly def: "Checking configuration failed"; + readonly es: "La verificación de configuración falló"; + readonly fr: "Échec de la vérification de la configuration"; + readonly he: "בדיקת התצורה נכשלה"; + readonly ja: "設定の確認に失敗しました"; + readonly ko: "구성 확인 실패"; + readonly ru: "Проверка конфигурации не удалась"; + readonly zh: "配置检查失败"; + }; + readonly "obsidianLiveSyncSettingTab.logCheckingDbConfig": { + readonly def: "Checking database configuration"; + readonly es: "Verificando la configuración de la base de datos"; + readonly fr: "Vérification de la configuration de la base"; + readonly he: "בודק תצורת מסד נתונים"; + readonly ja: "データベース設定を確認中"; + readonly ko: "데이터베이스 구성 확인 중"; + readonly ru: "Проверка конфигурации базы данных"; + readonly zh: "正在检查数据库配置"; + }; + readonly "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": { + readonly def: "ERROR: Failed to check passphrase with the remote server:\n${db}."; + readonly es: "ERROR: Error al comprobar la frase de contraseña con el servidor remoto: \n${db}."; + readonly fr: "ERREUR : Échec de la vérification de la phrase secrète avec le serveur distant :\n${db}."; + readonly he: "שגיאה: בדיקת ביטוי הסיסמה עם השרת המרוחד נכשלה:\n${db}."; + readonly ja: "エラー: リモートサーバーとのパスフレーズ確認に失敗しました:\n${db}。"; + readonly ko: "오류: 원격 서버와 패스프레이즈 확인에 실패했습니다: \n${db}."; + readonly ru: "ОШИБКА: Не удалось проверить пароль с удалённым сервером: db."; + readonly zh: "错误:无法使用远程服务器检查密码:\n${db} "; + }; + readonly "obsidianLiveSyncSettingTab.logConfiguredDisabled": { + readonly def: "Configured synchronization mode: DISABLED"; + readonly es: "Modo de sincronización configurado: DESACTIVADO"; + readonly fr: "Mode de synchronisation configuré : DÉSACTIVÉ"; + readonly he: "מצב סנכרון שהוגדר: מנוטרל"; + readonly ja: "設定された同期モード: 無効"; + readonly ko: "구성된 동기화 모드: 비활성화됨"; + readonly ru: "Настроенный режим синхронизации: ОТКЛЮЧЕН"; + readonly zh: "已配置的同步模式:已禁用"; + readonly "zh-tw": "已設定的同步模式:已停用"; + }; + readonly "obsidianLiveSyncSettingTab.logConfiguredLiveSync": { + readonly def: "Configured synchronization mode: LiveSync"; + readonly es: "Modo de sincronización configurado: Sincronización en Vivo"; + readonly fr: "Mode de synchronisation configuré : LiveSync"; + readonly he: "מצב סנכרון שהוגדר: LiveSync"; + readonly ja: "設定された同期モード: LiveSync"; + readonly ko: "구성된 동기화 모드: LiveSync"; + readonly ru: "Настроенный режим синхронизации: LiveSync"; + readonly zh: "已配置的同步模式:LiveSync"; + readonly "zh-tw": "已設定的同步模式:LiveSync"; + }; + readonly "obsidianLiveSyncSettingTab.logConfiguredPeriodic": { + readonly def: "Configured synchronization mode: Periodic"; + readonly es: "Modo de sincronización configurado: Periódico"; + readonly fr: "Mode de synchronisation configuré : Périodique"; + readonly he: "מצב סנכרון שהוגדר: תקופתי"; + readonly ja: "設定された同期モード: 定期"; + readonly ko: "구성된 동기화 모드: 주기적"; + readonly ru: "Настроенный режим синхронизации: Периодический"; + readonly zh: "已配置的同步模式:定期同步"; + readonly "zh-tw": "已設定的同步模式:定期同步"; + }; + readonly "obsidianLiveSyncSettingTab.logCouchDbConfigFail": { + readonly def: "CouchDB Configuration: ${title} failed"; + readonly es: "Configuración de CouchDB: ${title} falló"; + readonly fr: "Configuration CouchDB : échec de ${title}"; + readonly he: "תצורת CouchDB: ${title} נכשלה"; + readonly ja: "CouchDB設定: ${title} 失敗"; + readonly ko: "CouchDB 구성: ${title} 실패"; + readonly ru: "Конфигурация CouchDB: title не удалась"; + readonly zh: "CouchDB 配置:${title} 失败"; + }; + readonly "obsidianLiveSyncSettingTab.logCouchDbConfigSet": { + readonly def: "CouchDB Configuration: ${title} -> Set ${key} to ${value}"; + readonly es: "Configuración de CouchDB: ${title} -> Establecer ${key} en ${value}"; + readonly fr: "Configuration CouchDB : ${title} -> ${key} défini à ${value}"; + readonly he: "תצורת CouchDB: ${title} -> הגדר ${key} ל-${value}"; + readonly ja: "CouchDB設定: ${title} -> ${key}を${value}に設定"; + readonly ko: "CouchDB 구성: ${title} -> ${key}를 ${value}로 설정"; + readonly ru: "Конфигурация CouchDB: title -> Установить key в value"; + readonly zh: "CouchDB 配置:${title} -> 设置 ${key} 为 ${value}"; + }; + readonly "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": { + readonly def: "CouchDB Configuration: ${title} successfully updated"; + readonly es: "Configuración de CouchDB: ${title} actualizado correctamente"; + readonly fr: "Configuration CouchDB : ${title} mise à jour avec succès"; + readonly he: "תצורת CouchDB: ${title} עודכנה בהצלחה"; + readonly ja: "CouchDB設定: ${title} 正常に更新されました"; + readonly ko: "CouchDB 구성: ${title} 성공적으로 업데이트됨"; + readonly ru: "Конфигурация CouchDB: title успешно обновлена"; + readonly zh: "CouchDB 配置:${title} 成功更新"; + }; + readonly "obsidianLiveSyncSettingTab.logDatabaseConnected": { + readonly def: "Database connected"; + readonly es: "Base de datos conectada"; + readonly fr: "Base de données connectée"; + readonly he: "מסד הנתונים מחובר"; + readonly ja: "データベースに接続しました"; + readonly ko: "데이터베이스 연결됨"; + readonly ru: "База данных подключена"; + readonly zh: "数据库已连接"; + }; + readonly "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": { + readonly def: "You cannot enable encryption without a passphrase"; + readonly es: "No puedes habilitar el cifrado sin una frase de contraseña"; + readonly fr: "Impossible d'activer le chiffrement sans phrase secrète"; + readonly he: "לא ניתן להפעיל הצפנה ללא ביטוי סיסמה"; + readonly ja: "パスフレーズなしでは暗号化を有効にできません"; + readonly ko: "패스프레이즈 없이는 암호화를 활성화할 수 없습니다"; + readonly ru: "Вы не можете включить шифрование без парольной фразы"; + readonly zh: "没有密码无法启用加密"; + }; + readonly "obsidianLiveSyncSettingTab.logEncryptionNoSupport": { + readonly def: "Your device does not support encryption."; + readonly es: "Tu dispositivo no admite el cifrado."; + readonly fr: "Votre appareil ne prend pas en charge le chiffrement."; + readonly he: "המכשיר שלך אינו תומך בהצפנה."; + readonly ja: "お使いのデバイスは暗号化をサポートしていません。"; + readonly ko: "기기가 암호화를 지원하지 않습니다."; + readonly ru: "Ваше устройство не поддерживает шифрование."; + readonly zh: "您的设备不支持加密 "; + }; + readonly "obsidianLiveSyncSettingTab.logErrorOccurred": { + readonly def: "An error occurred!!"; + readonly es: "¡Ocurrió un error!"; + readonly fr: "Une erreur s'est produite !!"; + readonly he: "אירעה שגיאה!!"; + readonly ja: "エラーが発生しました!!"; + readonly ko: "오류가 발생했습니다!"; + readonly ru: "Произошла ошибка!!"; + readonly zh: "发生错误!!"; + }; + readonly "obsidianLiveSyncSettingTab.logEstimatedSize": { + readonly def: "Estimated size: ${size}"; + readonly es: "Tamaño estimado: ${size}"; + readonly fr: "Taille estimée : ${size}"; + readonly he: "גודל משוער: ${size}"; + readonly ja: "推定サイズ: ${size}"; + readonly ko: "예상 크기: ${size}"; + readonly ru: "Примерный размер: size"; + readonly zh: "估计大小:${size}"; + }; + readonly "obsidianLiveSyncSettingTab.logPassphraseInvalid": { + readonly def: "Passphrase is not valid, please fix it."; + readonly es: "La frase de contraseña no es válida, por favor corrígela."; + readonly fr: "La phrase secrète est invalide, veuillez la corriger."; + readonly he: "ביטוי הסיסמה אינו תקין, אנא תקן אותו."; + readonly ja: "パスフレーズが無効です、修正してください。"; + readonly ko: "패스프레이즈가 유효하지 않습니다. 수정해 주세요."; + readonly ru: "Парольная фраза недействительна, пожалуйста, исправьте."; + readonly zh: "密码无效,请修正"; + }; + readonly "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": { + readonly def: "ERROR: Passphrase is not compatible with the remote server! Please check it again!"; + readonly es: "ERROR: ¡La frase de contraseña no es compatible con el servidor remoto! ¡Por favor, revísala de nuevo!"; + readonly fr: "ERREUR : la phrase secrète n'est pas compatible avec le serveur distant ! Veuillez vérifier à nouveau !"; + readonly he: "שגיאה: ביטוי הסיסמה אינו תואם לשרת המרוחד! אנא בדוק שוב!"; + readonly ja: "エラー: パスフレーズがリモートサーバーと適合しません!再度確認してください!"; + readonly ko: "오류: 패스프레이즈가 원격 서버와 호환되지 않습니다! 다시 확인해 주세요!"; + readonly ru: "ОШИБКА: Парольная фраза несовместима с удалённым сервером!"; + readonly zh: "错误:密码与远程服务器不兼容!请再次检查!"; + }; + readonly "obsidianLiveSyncSettingTab.logRebuildNote": { + readonly def: "Syncing has been disabled, fetch and re-enabled if desired."; + readonly es: "La sincronización ha sido desactivada, obtén y vuelve a activar si lo deseas."; + readonly fr: "La synchronisation a été désactivée, récupérez et réactivez si souhaité."; + readonly he: "הסנכרון הושבת, משוך והפעל מחדש אם רצוי."; + readonly ja: "同期が無効になりました。必要に応じてフェッチして再有効化してください。"; + readonly ko: "동기화가 비활성화되었습니다. 원하는 경우 가져오기 후 다시 활성화하세요."; + readonly ru: "Синхронизация отключена, загрузите и включите снова при желании."; + readonly zh: "同步已禁用,如果需要,请获取并重新启用"; + }; + readonly "obsidianLiveSyncSettingTab.logSelectAnyPreset": { + readonly def: "Select any preset."; + readonly es: "Selecciona cualquier preestablecido."; + readonly fr: "Sélectionnez un préréglage."; + readonly he: "בחר קביעה מראש כלשהי."; + readonly ja: "プリセットを選択してください。"; + readonly ko: "프리셋을 선택하세요."; + readonly ru: "Выберите любой пресет."; + readonly zh: "请选择任一预设。"; + readonly "zh-tw": "請選擇任一預設項目。"; + }; + readonly "obsidianLiveSyncSettingTab.logServerConfigurationCheck": { + readonly def: "obsidianLiveSyncSettingTab.logServerConfigurationCheck"; + }; + readonly "obsidianLiveSyncSettingTab.msgAreYouSureProceed": { + readonly def: "Are you sure to proceed?"; + readonly es: "¿Estás seguro de proceder?"; + readonly fr: "Êtes-vous sûr de vouloir continuer ?"; + readonly he: "האם אתה בטוח שברצונך להמשיך?"; + readonly ja: "本当に続行しますか?"; + readonly ko: "정말로 진행하시겠습니까?"; + readonly ru: "Вы уверены, что хотите продолжить?"; + readonly zh: "您确定要继续吗?"; + }; + readonly "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": { + readonly def: "Changes need to be applied!"; + readonly es: "¡Los cambios deben aplicarse!"; + readonly fr: "Des modifications doivent être appliquées !"; + readonly he: "יש להחיל שינויים!"; + readonly ja: "変更を適用する必要があります!"; + readonly ko: "변경사항을 적용해야 합니다!"; + readonly ru: "Изменения нужно применить!"; + readonly zh: "需要应用更改!"; + }; + readonly "obsidianLiveSyncSettingTab.msgConfigCheck": { + readonly def: "--Config check--"; + readonly es: "--Verificación de configuración--"; + readonly fr: "--Vérification de la configuration--"; + readonly he: "--בדיקת תצורה--"; + readonly ja: "--設定確認--"; + readonly ko: "--구성 확인--"; + readonly ru: "--Проверка конфигурации--"; + readonly zh: "--配置检查--"; + }; + readonly "obsidianLiveSyncSettingTab.msgConfigCheckFailed": { + readonly def: "The configuration check has failed. Do you want to continue anyway?"; + readonly es: "La verificación de configuración ha fallado. ¿Quieres continuar de todos modos?"; + readonly fr: "La vérification de la configuration a échoué. Voulez-vous continuer malgré tout ?"; + readonly he: "בדיקת התצורה נכשלה. האם ברצונך להמשיך בכל זאת?"; + readonly ja: "設定確認に失敗しました。それでも続行しますか?"; + readonly ko: "구성 확인에 실패했습니다. 그래도 계속하시겠습니까?"; + readonly ru: "Проверка конфигурации не удалась. Вы всё равно хотите продолжить?"; + readonly zh: "配置检查失败。仍要继续吗?"; + readonly "zh-tw": "設定檢查失敗。仍要繼續嗎?"; + }; + readonly "obsidianLiveSyncSettingTab.msgConnectionCheck": { + readonly def: "--Connection check--"; + readonly es: "--Verificación de conexión--"; + readonly fr: "--Vérification de la connexion--"; + readonly he: "--בדיקת חיבור--"; + readonly ja: "--接続確認--"; + readonly ko: "--연결 확인--"; + readonly ru: "--Проверка подключения--"; + readonly zh: "--连接检查--"; + }; + readonly "obsidianLiveSyncSettingTab.msgConnectionProxyNote": { + readonly def: "If you're having trouble with the Connection-check (even after checking config), please check your reverse proxy configuration."; + readonly es: "Si tienes problemas con la verificación de conexión (incluso después de verificar la configuración), por favor verifica la configuración de tu proxy reverso."; + readonly fr: "Si vous rencontrez des problèmes de vérification de connexion (même après avoir vérifié la configuration), veuillez vérifier votre configuration de reverse proxy."; + readonly he: "אם אתה נתקל בבעיות עם בדיקת החיבור (גם לאחר בדיקת התצורה), אנא בדוק את הגדרות ה-reverse proxy שלך."; + readonly ja: "設定確認後も接続確認に問題がある場合は、リバースプロキシの設定を確認してください。"; + readonly ko: "구성 확인 후에도 연결 확인에 문제가 있는 경우, 리버스 프록시 구성을 확인해 주세요."; + readonly ru: "Если у вас проблемы с проверкой подключения, проверьте конфигурацию обратного прокси."; + readonly zh: "如果您在连接检查时遇到问题(即使检查了配置后),请检查您的反向代理配置"; + }; + readonly "obsidianLiveSyncSettingTab.msgCurrentOrigin": { + readonly def: "Current origin: ${origin}"; + readonly es: "Origen actual: {origin}"; + readonly fr: "Origine actuelle : ${origin}"; + readonly he: "מקור נוכחי: ${origin}"; + readonly ja: "現在のオリジン: ${origin}"; + readonly ko: "현재 원점: {origin}"; + readonly ru: "Текущий origin: origin"; + readonly zh: "当前源: {origin}"; + }; + readonly "obsidianLiveSyncSettingTab.msgDiscardConfirmation": { + readonly def: "Do you really want to discard existing settings and databases?"; + readonly es: "¿Realmente deseas descartar las configuraciones y bases de datos existentes?"; + readonly fr: "Voulez-vous vraiment abandonner les paramètres et bases existants ?"; + readonly he: "האם אתה בטוח שברצונך לבטל הגדרות ומסדי נתונים קיימים?"; + readonly ja: "本当に既存の設定とデータベースを破棄しますか?"; + readonly ko: "정말로 기존 설정과 데이터베이스를 삭제하시겠습니까?"; + readonly ru: "Вы действительно хотите отменить существующие настройки и базы данных?"; + readonly zh: "您真的要丢弃现有的设置和数据库吗?"; + }; + readonly "obsidianLiveSyncSettingTab.msgDone": { + readonly def: "--Done--"; + readonly es: "--Hecho--"; + readonly fr: "--Terminé--"; + readonly he: "--הסתיים--"; + readonly ja: "--完了--"; + readonly ko: "--완료--"; + readonly ru: "--Готово--"; + readonly zh: "--完成--"; + }; + readonly "obsidianLiveSyncSettingTab.msgEnableCors": { + readonly def: "Set httpd.enable_cors"; + readonly es: "Configurar httpd.enable_cors"; + readonly fr: "Définir httpd.enable_cors"; + readonly he: "הגדר httpd.enable_cors"; + readonly ja: "httpd.enable_corsを設定"; + readonly ko: "httpd.enable_cors 설정"; + readonly ru: "Установить httpd.enable_cors"; + readonly zh: "设置 httpd.enable_cors"; + }; + readonly "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": { + readonly def: "Set chttpd.enable_cors"; + readonly fr: "Définir chttpd.enable_cors"; + readonly he: "הגדר chttpd.enable_cors"; + readonly ja: "chttpd.enable_corsを設定"; + readonly ru: "Установить chttpd.enable_cors"; + readonly zh: "设置 chttpd.enable_cors"; + }; + readonly "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": { + readonly def: "We recommend enabling End-To-End Encryption, and Path Obfuscation. Are you sure you want to continue without encryption?"; + readonly es: "Recomendamos habilitar el cifrado de extremo a extremo y la obfuscación de ruta. ¿Estás seguro de querer continuar sin cifrado?"; + readonly fr: "Nous recommandons d'activer le chiffrement de bout en bout et l'obfuscation des chemins. Êtes-vous sûr de vouloir continuer sans chiffrement ?"; + readonly he: "אנו ממליצים להפעיל הצפנה מקצה לקצה ואת ערפול הנתיב. האם אתה בטוח שברצונך להמשיך ללא הצפנה?"; + readonly ja: "エンドツーエンド暗号化とパス難読化を有効にすることをお勧めします。暗号化なしで続行してもよろしいですか?"; + readonly ko: "종단간 암호화와 경로 난독화를 활성화하는 것을 권장합니다. 정말로 암호화 없이 계속하시겠습니까?"; + readonly ru: "Мы рекомендуем включить сквозное шифрование. Вы уверены, что хотите продолжить без шифрования?"; + readonly zh: "建议启用端到端加密和路径混淆。你确定要在未加密的情况下继续吗?"; + readonly "zh-tw": "我們建議啟用端對端加密與路徑混淆。你確定要在未加密的情況下繼續嗎?"; + }; + readonly "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": { + readonly def: "Do you want to fetch the config from the remote server?"; + readonly es: "¿Quieres obtener la configuración del servidor remoto?"; + readonly fr: "Voulez-vous récupérer la configuration depuis le serveur distant ?"; + readonly he: "האם ברצונך למשוך את התצורה מהשרת המרוחד?"; + readonly ja: "リモートサーバーから設定を取得しますか?"; + readonly ko: "원격 서버에서 구성을 가져오시겠습니까?"; + readonly ru: "Вы хотите загрузить конфигурацию с удалённого сервера?"; + readonly zh: "要从远端服务器获取配置吗?"; + readonly "zh-tw": "要從遠端伺服器抓取設定嗎?"; + }; + readonly "obsidianLiveSyncSettingTab.msgGenerateSetupURI": { + readonly def: "All done! Do you want to generate a setup URI to set up other devices?"; + readonly es: "¡Todo listo! ¿Quieres generar un URI de configuración para configurar otros dispositivos?"; + readonly fr: "Tout est prêt ! Voulez-vous générer une URI de configuration pour configurer d'autres appareils ?"; + readonly he: "הכל מוכן! האם ברצונך לייצר Setup URI להגדרת מכשירים אחרים?"; + readonly ja: "完了!他のデバイスをセットアップするためのセットアップURIを生成しますか?"; + readonly ko: "모든 작업이 완료되었습니다! 다른 기기를 설정하기 위해 Setup URI를 생성하시겠습니까?"; + readonly ru: "Всё готово! Вы хотите сгенерировать Setup URI для настройки других устройств?"; + readonly zh: "全部完成!要生成设置 URI 以便配置其他设备吗?"; + readonly "zh-tw": "全部完成!要產生 Setup URI 以便設定其他裝置嗎?"; + }; + readonly "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": { + readonly def: "If the server configuration is not persistent (e.g., running on docker), the values here may change. Once you are able to connect, please update the settings in the server's local.ini."; + readonly es: "Si la configuración del servidor no es persistente (por ejemplo, ejecutándose en docker), los valores aquí pueden cambiar. Una vez que puedas conectarte, por favor actualiza las configuraciones en el local.ini del servidor."; + readonly fr: "Si la configuration du serveur n'est pas persistante (par ex. fonctionnant sur Docker), les valeurs peuvent changer. Une fois la connexion établie, mettez à jour les paramètres dans le local.ini du serveur."; + readonly he: "אם תצורת השרת אינה קבועה (למשל, פועלת ב-docker), הערכים כאן עשויים להשתנות. לאחר שתצליח להתחבר, אנא עדכן את ההגדרות ב-local.ini של השרת."; + readonly ja: "サーバー設定が永続的でない場合(例: Dockerで実行中)、ここの値は変更される可能性があります。接続できるようになったら、サーバーのlocal.iniの設定を更新してください。"; + readonly ko: "서버 설정이 영구적으로 저장되지 않는 환경(예: Docker에서 실행 중)에서는 이곳의 값들이 변경될 수 있습니다. 연결이 가능해지면 서버의 local.ini 파일에서 설정을 수동으로 업데이트해 주세요."; + readonly ru: "Если конфигурация сервера непостоянна, значения здесь могут измениться."; + readonly zh: "如果服务器配置不是持久的(例如,在 docker 上运行),此处的值可能会更改。一旦能够连接,请更新服务器 local.ini 中的设置"; + }; + readonly "obsidianLiveSyncSettingTab.msgInvalidPassphrase": { + readonly def: "Your encryption passphrase might be invalid. Are you sure you want to continue?"; + readonly es: "Tu frase de contraseña de cifrado podría ser inválida. ¿Estás seguro de querer continuar?"; + readonly fr: "Votre phrase secrète de chiffrement peut être invalide. Êtes-vous sûr de vouloir continuer ?"; + readonly he: "ביטוי הסיסמה להצפנה שלך עשוי להיות לא תקין. האם אתה בטוח שברצונך להמשיך?"; + readonly ja: "暗号化パスフレーズが無効かもしれません。続行してもよろしいですか?"; + readonly ko: "암호화 패스프레이즈가 유효하지 않을 수 있습니다. 정말로 계속하시겠습니까?"; + readonly ru: "Ваша парольная фраза шифрования может быть недействительна."; + readonly zh: "你的加密密码短语可能无效。你确定要继续吗?"; + readonly "zh-tw": "你的加密密語可能無效。你確定要繼續嗎?"; + }; + readonly "obsidianLiveSyncSettingTab.msgNewVersionNote": { + readonly def: "Here due to an upgrade notification? Please review the version history. If you're satisfied, click the button. A new update will prompt this again."; + readonly es: "¿Aquí debido a una notificación de actualización? Por favor, revise el historial de versiones. Si está satisfecho, haga clic en el botón. Una nueva actualización volverá a mostrar esto."; + readonly fr: "Arrivé ici suite à une notification de mise à jour ? Consultez l'historique des versions. Si vous êtes satisfait, cliquez sur le bouton. Une nouvelle mise à jour reproposera ceci."; + readonly he: "הגעת כאן בשל הודעת שדרוג? אנא עיין בהיסטוריית הגרסאות. אם אתה מרוצה, לחץ על הכפתור. עדכון חדש יציג זאת שוב."; + readonly ja: "アップグレード通知でここに来ましたか?バージョン履歴を確認してください。納得したらボタンをクリックしてください。新しい更新があると再度確認されます。"; + readonly ko: "업그레이드 알림으로 여기에 오셨나요? 버전 기록을 검토해 주세요. 만족하신다면 버튼을 클릭하세요. 새로운 업데이트 시 다시 안내됩니다."; + readonly ru: "Вы пришли из-за уведомления об обновлении? Просмотрите историю версий."; + readonly zh: "因为升级通知来到这里?请查看版本历史。如果您满意,请点击按钮。新的更新将再次提示此信息"; + }; + readonly "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": { + readonly def: "Configured as non-HTTPS URI. Be warned that this may not work on mobile devices."; + readonly es: "Configurado como URI que no es HTTPS. Ten en cuenta que esto puede no funcionar en dispositivos móviles."; + readonly fr: "Configuré avec une URI non HTTPS. Attention, ceci peut ne pas fonctionner sur les appareils mobiles."; + readonly he: "מוגדר כ-URI שאינו HTTPS. שים לב שהדבר עשוי שלא לפעול על מכשירים ניידים."; + readonly ja: "非HTTPS URIとして設定されています。モバイルデバイスでは動作しない可能性があります。"; + readonly ko: "비 HTTPS URI로 구성되었습니다. 모바일 기기에서는 작동하지 않을 수 있으니 주의하세요."; + readonly ru: "Настроено как не-HTTPS URI. Это может не работать на мобильных устройствах."; + readonly zh: "配置为非 HTTPS URI。请注意,这可能在移动设备上无法工作"; + }; + readonly "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": { + readonly def: "Cannot connect to non-HTTPS URI. Please update your config and try again."; + readonly es: "No se puede conectar a URI que no sean HTTPS. Por favor, actualiza tu configuración y vuelve a intentarlo."; + readonly fr: "Connexion impossible à une URI non HTTPS. Mettez à jour votre configuration et réessayez."; + readonly he: "לא ניתן להתחבר ל-URI שאינו HTTPS. אנא עדכן את התצורה ונסה שוב."; + readonly ja: "非HTTPS URIに接続できません。設定を更新して再試行してください。"; + readonly ko: "비 HTTPS URI에 연결할 수 없습니다. 구성을 업데이트하고 다시 시도해 주세요."; + readonly ru: "Не удаётся подключиться к не-HTTPS URI. Обновите конфигурацию."; + readonly zh: "无法连接到非 HTTPS URI。请更新您的配置并重试"; + }; + readonly "obsidianLiveSyncSettingTab.msgNotice": { + readonly def: "---Notice---"; + readonly es: "---Aviso---"; + readonly fr: "---Avis---"; + readonly he: "---הודעה---"; + readonly ja: "---お知らせ---"; + readonly ko: "---공지사항---"; + readonly ru: "---Уведомление---"; + readonly zh: "---注意---"; + }; + readonly "obsidianLiveSyncSettingTab.msgObjectStorageWarning": { + readonly def: "WARNING: This feature is a Work In Progress, so please keep in mind the following:\n- Append only architecture. A rebuild is required to shrink the storage.\n- A bit fragile.\n- When first syncing, all history will be transferred from the remote. Be mindful of data caps and slow speeds.\n- Only differences are synced live.\n\nIf you run into any issues, or have ideas about this feature, please create a issue on GitHub.\nI appreciate you for your great dedication."; + readonly es: "ADVERTENCIA: Esta característica está en desarrollo, así que por favor ten en cuenta lo siguiente:\n- Arquitectura de solo anexado. Se requiere una reconstrucción para reducir el almacenamiento.\n- Un poco frágil.\n- Al sincronizar por primera vez, todo el historial será transferido desde el remoto. Ten en cuenta los límites de datos y las velocidades lentas.\n- Solo las diferencias se sincronizan en vivo.\n\nSi encuentras algún problema o tienes ideas sobre esta característica, por favor crea un issue en GitHub.\nAprecio mucho tu gran dedicación."; + readonly fr: "AVERTISSEMENT : cette fonctionnalité est en cours de développement, gardez à l'esprit ce qui suit :\n- Architecture en ajout seul. Une reconstruction est nécessaire pour réduire le stockage.\n- Un peu fragile.\n- Lors de la première synchronisation, tout l'historique sera transféré depuis le distant. Attention aux limites de données et aux débits lents.\n- Seules les différences sont synchronisées en direct.\n\nSi vous rencontrez des problèmes ou avez des idées sur cette fonctionnalité, merci d'ouvrir un ticket sur GitHub.\nMerci pour votre grand dévouement."; + readonly he: "אזהרה: תכונה זו בשלב פיתוח, לכן שים לב לנקודות הבאות:\n- ארכיטקטורת הוספה בלבד. נדרשת בנייה מחדש לצמצום האחסון.\n- קצת רגיש.\n- בסנכרון הראשון, כל ההיסטוריה תועבר מהשרת המרוחד. שים לב למגבלות נתונים ומהירות.\n- רק הפרשים מסונכרנים בזמן אמת.\n\nאם נתקלת בבעיות, או שיש לך רעיונות לגבי תכונה זו, אנא פתח Issue ב-GitHub.\nאנחנו מעריכים את ההקדשה הגדולה שלך."; + readonly ja: "警告: この機能は開発中です。以下の点にご注意ください:\n- 追記専用アーキテクチャ。ストレージを縮小するには再構築が必要です。\n- やや不安定です。\n- 初回同期時、すべての履歴がリモートから転送されます。データ制限と速度に注意してください。\n- ライブ同期は差分のみです。\n\n問題があれば、またはこの機能についてアイデアがあれば、GitHubにIssueを作成してください。\nご協力に感謝します。"; + readonly ko: "⚠️ 주의: 이 기능은 아직 개발 중(WIP)입니다. 다음 사항을 유의해 주세요:\n- 추가 전용 구조(append-only)로 동작합니다. 저장 용량을 줄이려면 데이터 재구성이 필요합니다.\n- 기능이 다소 불안정할 수 있습니다.\n- 최초 동기화 시, 전체 히스토리가 원격 서버에서 전송됩니다. 데이터 용량 제한 및 느린 속도에 유의해 주세요.\n- 실시간 동기화는 변경된 부분만 처리됩니다.\n\n문제가 발생했거나 개선 아이디어가 있으시면 GitHub에 이슈를 등록해 주세요.\n기여에 깊이 감사드립니다."; + readonly ru: "ПРЕДУПРЕЖДЕНИЕ: Эта функция в разработке."; + readonly zh: "警告:此功能仍在开发中,请注意以下几点:\n- 仅追加架构。需要重建才能缩小存储空间。\n- 有点脆弱。\n- 首次同步时,所有历史记录将从远程传输。注意数据上限和慢速。\n- 只有差异会实时同步。\n\n如果您遇到任何问题,或对此功能有任何想法,请在 GitHub 上创建 issue。\n感谢您的巨大贡献"; + }; + readonly "obsidianLiveSyncSettingTab.msgOriginCheck": { + readonly def: "Origin check: ${org}"; + readonly es: "Verificación de origen: {org}"; + readonly fr: "Vérification d'origine : ${org}"; + readonly he: "בדיקת מקור: ${org}"; + readonly ja: "オリジン確認: ${org}"; + readonly ko: "원점 확인: {org}"; + readonly ru: "Проверка origin: org"; + readonly zh: "源检查: {org}"; + }; + readonly "obsidianLiveSyncSettingTab.msgRebuildRequired": { + readonly def: "Rebuilding Databases are required to apply the changes.. Please select the method to apply the changes.\n\n
\nLegends\n\n| Symbol | Meaning |\n|: ------ :| ------- |\n| ⇔ | Up to Date |\n| ⇄ | Synchronise to balance |\n| ⇐,⇒ | Transfer to overwrite |\n| ⇠,⇢ | Transfer to overwrite from other side |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\nAt a glance: 📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\nReconstruct both the local and remote databases using existing files from this device.\nThis causes a lockout other devices, and they need to perform fetching.\n## ${OPTION_FETCH}\nAt a glance: 📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\nInitialise the local database and reconstruct it using data fetched from the remote database.\nThis case includes the case which you have rebuilt the remote database.\n## ${OPTION_ONLY_SETTING}\nStore only the settings. **Caution: This may lead to data corruption**; database reconstruction is generally necessary."; + readonly es: "Es necesario reconstruir las bases de datos para aplicar los cambios. Por favor selecciona el método para aplicar los cambios.\n\n
\nLegendas\n\n| Símbolo | Significado |\n|: ------ :| ------- |\n| ⇔ | Actualizado |\n| ⇄ | Sincronizar para equilibrar |\n| ⇐,⇒ | Transferir para sobrescribir |\n| ⇠,⇢ | Transferir para sobrescribir desde otro lado |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\nA simple vista: 📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\nReconstruir tanto la base de datos local como la remota utilizando los archivos existentes de este dispositivo.\nEsto bloquea a otros dispositivos, y necesitan realizar la obtención.\n## ${OPTION_FETCH}\nA simple vista: 📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\nInicializa la base de datos local y la reconstruye utilizando los datos obtenidos de la base de datos remota.\nEste caso incluye el caso en el que has reconstruido la base de datos remota.\n## ${OPTION_ONLY_SETTING}\nAlmacena solo la configuración. **Precaución: esto puede provocar corrupción de datos**; generalmente es necesario reconstruir la base de datos."; + readonly fr: "La reconstruction des bases de données est nécessaire pour appliquer les changements. Veuillez sélectionner la méthode d'application.\n\n
\nLégende\n\n| Symbole | Signification |\n|: ------ :| ------- |\n| ⇔ | À jour |\n| ⇄ | Synchroniser pour équilibrer |\n| ⇐,⇒ | Transférer pour écraser |\n| ⇠,⇢ | Transférer pour écraser depuis l'autre côté |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\nEn bref : 📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\nReconstruit les bases locale et distante à partir des fichiers existants de cet appareil.\nCeci provoque un verrouillage des autres appareils, qui devront effectuer une récupération.\n## ${OPTION_FETCH}\nEn bref : 📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\nInitialise la base locale et la reconstruit à partir des données récupérées depuis la base distante.\nCe cas inclut également celui où vous avez reconstruit la base distante.\n## ${OPTION_ONLY_SETTING}\nNe stocker que les paramètres. **Attention : cela peut entraîner une corruption des données** ; une reconstruction de la base est généralement nécessaire."; + readonly he: "נדרשת בנייה מחדש של מסדי הנתונים כדי להחיל את השינויים. אנא בחר את השיטה.\n\n
\nמקרא\n\n| סמל | משמעות |\n|: ------ :| ------- |\n| ⇔ | מעודכן |\n| ⇄ | סנכרן לאיזון |\n| ⇐,⇒ | העבר לדריסה |\n| ⇠,⇢ | העבר לדריסה מהצד השני |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\nבמבט: 📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\nבנה מחדש גם את מסד הנתונים המקומי וגם המרוחד תוך שימוש בקבצים קיימים ממכשיר זה.\nפעולה זו תנעל מכשירים אחרים שיצטרכו לבצע משיכה.\n## ${OPTION_FETCH}\nבמבט: 📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\nאתחל את מסד הנתונים המקומי ובנה אותו מחדש תוך שימוש בנתונים שנמשכו ממסד הנתונים המרוחד.\nכולל את המקרה שבו בנית מחדש את מסד הנתונים המרוחד.\n## ${OPTION_ONLY_SETTING}\nשמור רק את ההגדרות. **זהירות: עלול לגרום לפגיעה בנתונים**; בנייה מחדש של מסד הנתונים נדרשת בדרך כלל."; + readonly ja: "変更を適用するにはデータベースの再構築が必要です。変更を適用する方法を選択してください。\n\n
\n凡例\n\n| 記号 | 意味 |\n|: ------ :| ------- |\n| ⇔ | 最新 |\n| ⇄ | 同期してバランスを取る |\n| ⇐,⇒ | 上書きするため転送 |\n| ⇠,⇢ | 反対側から上書きするため転送 |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\n概要: 📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\nこのデバイスの既存ファイルを使用してローカルとリモートの両方のデータベースを再構築します。\n他のデバイスはロックアウトされ、フェッチが必要です。\n## ${OPTION_FETCH}\n概要: 📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\nローカルデータベースを初期化し、リモートデータベースから取得したデータを使用して再構築します。\nリモートデータベースを再構築した場合も含まれます。\n## ${OPTION_ONLY_SETTING}\n設定のみを保存します。**注意: データ破損につながる可能性があります**。通常、データベースの再構築が必要です。"; + readonly ko: "변경사항을 적용하려면 데이터베이스를 재구축해야 합니다. 아래 중 한 가지 방법을 선택해 주세요.\n\n
\n범례\n\n| 기호 | 의미 |\n|: ------ :| ------- |\n| ⇔ | 최신 상태 |\n| ⇄ | 동기화 균형 유지 |\n| ⇐,⇒ | 덮어쓰기 방식의 전송 |\n| ⇠,⇢ | 상대편에서 가져와 덮어쓰기 |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\n개요: 📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\n이 기기의 기존 파일을 기반으로 로컬과 원격 데이터베이스를 모두 재구축합니다.\n이 과정에서 다른 기기는 일시적으로 접근이 제한되며, 가져오기 작업을 별도로 수행해야 합니다.\n\n## ${OPTION_FETCH}\n개요: 📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\n로컬 데이터베이스를 초기화한 후, 원격 데이터베이스에서 데이터를 가져와 재구축합니다.\n이는 원격 측에서 데이터베이스를 먼저 재구축한 경우에도 해당됩니다.\n\n## ${OPTION_ONLY_SETTING}\n설정만 저장합니다. **⚠️ 주의: 이 방법은 데이터 손상을 일으킬 수 있습니다.** 일반적으로는 전체 데이터베이스 재구축이 필요합니다."; + readonly ru: "Требуется перестроение баз данных для применения изменений."; + readonly zh: "需要重建数据库以应用更改。请选择应用更改的方法。\n\n
\n图例\n\n| 符号 | 含义 |\n|: ------ :| ------- |\n| ⇔ | 最新 |\n| ⇄ | 同步以平衡 |\n| ⇐,⇒ | 传输以覆盖 |\n| ⇠,⇢ | 从另一侧传输以覆盖 |\n\n
\n\n## ${OPTION_REBUILD_BOTH}\n概览:📄 ⇒¹ 💻 ⇒² 🛰️ ⇢ⁿ 💻 ⇄ⁿ⁺¹ 📄\n使用此设备的现有文件重建本地和远程数据库。\n这将导致其他设备被锁定,并且它们需要执行获取操作。\n## ${OPTION_FETCH}\n概览:📄 ⇄² 💻 ⇐¹ 🛰️ ⇔ 💻 ⇔ 📄\n初始化本地数据库并使用从远程数据库获取的数据重建它。\n这种情况包括您已经重建了远程数据库的情况。\n## ${OPTION_ONLY_SETTING}\n仅存储设置。**注意:这可能导致数据损坏**;通常需要重建数据库"; + }; + readonly "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": { + readonly def: "Please select and apply any preset item to complete the wizard."; + readonly es: "Por favor, selecciona y aplica cualquier elemento preestablecido para completar el asistente."; + readonly fr: "Veuillez sélectionner et appliquer un préréglage pour terminer l'assistant."; + readonly he: "אנא בחר והחל פריט קבוע מראש כלשהו להשלמת האשף."; + readonly ja: "ウィザードを完了するには、プリセット項目を選択して適用してください。"; + readonly ko: "마법사를 완료하려면 프리셋 항목을 선택하고 적용해 주세요."; + readonly ru: "Выберите и примените любой пресет для завершения мастера."; + readonly zh: "请选择并应用任一预设项以完成向导。"; + readonly "zh-tw": "請選擇並套用任一預設項目以完成精靈。"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetCorsCredentials": { + readonly def: "Set cors.credentials"; + readonly es: "Configurar cors.credentials"; + readonly fr: "Définir cors.credentials"; + readonly he: "הגדר cors.credentials"; + readonly ja: "cors.credentialsを設定"; + readonly ko: "cors.credentials 설정"; + readonly ru: "Установить cors.credentials"; + readonly zh: "设置 cors.credentials"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetCorsOrigins": { + readonly def: "Set cors.origins"; + readonly es: "Configurar cors.origins"; + readonly fr: "Définir cors.origins"; + readonly he: "הגדר cors.origins"; + readonly ja: "cors.originsを設定"; + readonly ko: "cors.origins 설정"; + readonly ru: "Установить cors.origins"; + readonly zh: "设置 cors.origins"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetMaxDocSize": { + readonly def: "Set couchdb.max_document_size"; + readonly es: "Configurar couchdb.max_document_size"; + readonly fr: "Définir couchdb.max_document_size"; + readonly he: "הגדר couchdb.max_document_size"; + readonly ja: "couchdb.max_document_sizeを設定"; + readonly ko: "couchdb.max_document_size 설정"; + readonly ru: "Установить couchdb.max_document_size"; + readonly zh: "设置 couchdb.max_document_size"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": { + readonly def: "Set chttpd.max_http_request_size"; + readonly es: "Configurar chttpd.max_http_request_size"; + readonly fr: "Définir chttpd.max_http_request_size"; + readonly he: "הגדר chttpd.max_http_request_size"; + readonly ja: "chttpd.max_http_request_sizeを設定"; + readonly ko: "chttpd.max_http_request_size 설정"; + readonly ru: "Установить chttpd.max_http_request_size"; + readonly zh: "设置 chttpd.max_http_request_size"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetRequireValidUser": { + readonly def: "Set chttpd.require_valid_user = true"; + readonly es: "Configurar chttpd.require_valid_user = true"; + readonly fr: "Définir chttpd.require_valid_user = true"; + readonly he: "הגדר chttpd.require_valid_user = true"; + readonly ja: "chttpd.require_valid_user = trueを設定"; + readonly ko: "chttpd.require_valid_user = true로 설정"; + readonly ru: "Установить chttpd.require_valid_user = true"; + readonly zh: "设置 chttpd.require_valid_user = true"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": { + readonly def: "Set chttpd_auth.require_valid_user = true"; + readonly es: "Configurar chttpd_auth.require_valid_user = true"; + readonly fr: "Définir chttpd_auth.require_valid_user = true"; + readonly he: "הגדר chttpd_auth.require_valid_user = true"; + readonly ja: "chttpd_auth.require_valid_user = trueを設定"; + readonly ko: "chttpd_auth.require_valid_user = true로 설정"; + readonly ru: "Установить chttpd_auth.require_valid_user = true"; + readonly zh: "设置 chttpd_auth.require_valid_user = true"; + }; + readonly "obsidianLiveSyncSettingTab.msgSettingModified": { + readonly def: "The setting \"${setting}\" was modified from another device. Click {HERE} to reload settings. Click elsewhere to ignore changes."; + readonly es: "La configuración \"${setting}\" fue modificada desde otro dispositivo. Haz clic {HERE} para recargar la configuración. Haz clic en otro lugar para ignorar los cambios."; + readonly fr: "Le paramètre « ${setting} » a été modifié depuis un autre appareil. Cliquez sur {HERE} pour recharger les paramètres. Cliquez ailleurs pour ignorer les modifications."; + readonly he: "ההגדרה \"${setting}\" שונתה ממכשיר אחר. לחץ על {HERE} לטעינה מחדש של ההגדרות. לחץ במקום אחר להתעלמות מהשינויים."; + readonly ja: "設定\"${setting}\"が別のデバイスから変更されました。{HERE}をクリックして設定を再読み込みしてください。変更を無視するには他の場所をクリックしてください。"; + readonly ko: "\"${setting}\" 설정이 다른 기기에서 수정되었습니다. 설정을 다시 로드하려면 {HERE}를 클릭하세요. 변경사항을 무시하려면 다른 곳을 클릭하세요."; + readonly ru: "Настройка setting была изменена с другого устройства."; + readonly zh: "设置 \"${setting}\" 已从另一台设备修改。点击 {HERE} 重新加载设置。点击其他地方忽略更改"; + }; + readonly "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": { + readonly def: "These settings are unable to be changed during synchronization. Please disable all syncing in the \"Sync Settings\" to unlock."; + readonly es: "Estas configuraciones no se pueden cambiar durante la sincronización. Por favor, deshabilita toda la sincronización en las \"Configuraciones de Sincronización\" para desbloquear."; + readonly fr: "Ces paramètres ne peuvent pas être modifiés durant la synchronisation. Désactivez toute synchronisation dans « Paramètres de synchronisation » pour déverrouiller."; + readonly he: "הגדרות אלה אינן ניתנות לשינוי במהלך סנכרון. אנא נטרל את כל הסנכרון ב\"הגדרות סנכרון\" כדי לבטל נעילה."; + readonly ja: "これらの設定は同期中に変更できません。ロックを解除するには、\"同期設定\"ですべての同期を無効にしてください。"; + readonly ko: "동기화 중에는 이 설정들을 변경할 수 없습니다. 잠금을 해제하려면 \"동기화 설정\"에서 모든 동기화를 비활성화해 주세요."; + readonly ru: "Эти настройки нельзя изменить во время синхронизации."; + readonly zh: "这些设置在同步期间无法更改。请在“同步设置”中禁用所有同步以解锁"; + }; + readonly "obsidianLiveSyncSettingTab.msgSetWwwAuth": { + readonly def: "Set httpd.WWW-Authenticate"; + readonly es: "Configurar httpd.WWW-Authenticate"; + readonly fr: "Définir httpd.WWW-Authenticate"; + readonly he: "הגדר httpd.WWW-Authenticate"; + readonly ja: "httpd.WWW-Authenticateを設定"; + readonly ko: "httpd.WWW-Authenticate 설정"; + readonly ru: "Установить httpd.WWW-Authenticate"; + readonly zh: "设置 httpd.WWW-Authenticate"; + }; + readonly "obsidianLiveSyncSettingTab.nameApplySettings": { + readonly def: "Apply Settings"; + readonly es: "Aplicar configuraciones"; + readonly fr: "Appliquer les paramètres"; + readonly he: "החל הגדרות"; + readonly ja: "設定を適用"; + readonly ko: "설정 적용"; + readonly ru: "Применить настройки"; + readonly zh: "应用设置"; + }; + readonly "obsidianLiveSyncSettingTab.nameConnectSetupURI": { + readonly def: "Connect with Setup URI"; + readonly es: "Conectar con URI de configuración"; + readonly fr: "Se connecter avec une URI de configuration"; + readonly he: "התחבר עם Setup URI"; + readonly ja: "セットアップURIで接続"; + readonly ko: "Setup URI로 연결"; + readonly ru: "Подключиться через Setup URI"; + readonly zh: "使用设置 URI 连接"; + }; + readonly "obsidianLiveSyncSettingTab.nameCopySetupURI": { + readonly def: "Copy the current settings to a Setup URI"; + readonly es: "Copiar la configuración actual a una URI de configuración"; + readonly fr: "Copier les paramètres actuels vers une URI de configuration"; + readonly he: "העתק הגדרות נוכחיות ל-Setup URI"; + readonly ja: "現在の設定をセットアップURIにコピー"; + readonly ko: "현재 설정을 Setup URI로 복사"; + readonly ru: "Копировать текущие настройки в Setup URI"; + readonly zh: "将当前设置复制为设置 URI"; + }; + readonly "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": { + readonly def: "Disable Hidden files sync"; + readonly es: "Desactivar sincronización de archivos ocultos"; + readonly fr: "Désactiver la synchronisation des fichiers cachés"; + readonly he: "נטרל סנכרון קבצים נסתרים"; + readonly ja: "隠しファイル同期を無効化"; + readonly ko: "숨김 파일 동기화 비활성화"; + readonly ru: "Отключить синхронизацию скрытых файлов"; + readonly zh: "禁用隐藏文件同步"; + readonly "zh-tw": "停用隱藏檔案同步"; + }; + readonly "obsidianLiveSyncSettingTab.nameDiscardSettings": { + readonly def: "Discard existing settings and databases"; + readonly es: "Descartar configuraciones y bases de datos existentes"; + readonly fr: "Abandonner les paramètres et bases existants"; + readonly he: "בטל הגדרות ומסדי נתונים קיימים"; + readonly ja: "既存の設定とデータベースを破棄"; + readonly ko: "기존 설정 및 데이터베이스 삭제"; + readonly ru: "Отменить существующие настройки и базы данных"; + readonly zh: "丢弃现有设置和数据库"; + }; + readonly "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": { + readonly def: "Enable Hidden files sync"; + readonly es: "Activar sincronización de archivos ocultos"; + readonly fr: "Activer la synchronisation des fichiers cachés"; + readonly he: "הפעל סנכרון קבצים נסתרים"; + readonly ja: "隠しファイル同期を有効化"; + readonly ko: "숨김 파일 동기화 활성화"; + readonly ru: "Включить синхронизацию скрытых файлов"; + readonly zh: "启用隐藏文件同步"; + readonly "zh-tw": "啟用隱藏檔案同步"; + }; + readonly "obsidianLiveSyncSettingTab.nameEnableLiveSync": { + readonly def: "Enable LiveSync"; + readonly es: "Activar LiveSync"; + readonly fr: "Activer LiveSync"; + readonly he: "הפעל LiveSync"; + readonly ja: "LiveSyncを有効化"; + readonly ko: "LiveSync 활성화"; + readonly ru: "Включить LiveSync"; + readonly zh: "启用 LiveSync"; + }; + readonly "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": { + readonly def: "Hidden file synchronization"; + readonly es: "Sincronización de archivos ocultos"; + readonly fr: "Synchronisation des fichiers cachés"; + readonly he: "סנכרון קבצים נסתרים"; + readonly ja: "隠しファイル同期"; + readonly ko: "숨김 파일 동기화"; + readonly ru: "Синхронизация скрытых файлов"; + readonly zh: "隐藏文件同步"; + readonly "zh-tw": "隱藏檔案同步"; + }; + readonly "obsidianLiveSyncSettingTab.nameManualSetup": { + readonly def: "Manual Setup"; + readonly es: "Configuración manual"; + readonly fr: "Configuration manuelle"; + readonly he: "הגדרה ידנית"; + readonly ja: "手動セットアップ"; + readonly ko: "수동 설정"; + readonly ru: "Ручная настройка"; + readonly zh: "手动设置"; + }; + readonly "obsidianLiveSyncSettingTab.nameTestConnection": { + readonly def: "Test Connection"; + readonly es: "Probar conexión"; + readonly fr: "Tester la connexion"; + readonly he: "בדוק חיבור"; + readonly ja: "接続テスト"; + readonly ko: "연결 테스트"; + readonly ru: "Тест подключения"; + readonly zh: "测试连接"; + }; + readonly "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": { + readonly def: "Test Database Connection"; + readonly es: "Probar Conexión de Base de Datos"; + readonly fr: "Tester la connexion à la base de données"; + readonly he: "בדוק חיבור למסד נתונים"; + readonly ja: "データベース接続テスト"; + readonly ko: "데이터베이스 연결 테스트"; + readonly ru: "Тест подключения к базе данных"; + readonly zh: "测试数据库连接"; + }; + readonly "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": { + readonly def: "Validate Database Configuration"; + readonly es: "Validar Configuración de la Base de Datos"; + readonly fr: "Valider la configuration de la base de données"; + readonly he: "אמת תצורת מסד נתונים"; + readonly ja: "データベース設定を検証"; + readonly ko: "데이터베이스 구성 검증"; + readonly ru: "Проверить конфигурацию базы данных"; + readonly zh: "验证数据库配置"; + }; + readonly "obsidianLiveSyncSettingTab.okAdminPrivileges": { + readonly def: "✔ You have administrator privileges."; + readonly es: "✔ Tienes privilegios de administrador."; + readonly fr: "✔ Vous disposez des privilèges administrateur."; + readonly he: "✔ יש לך הרשאות מנהל."; + readonly ja: "✔ 管理者権限があります。"; + readonly ko: "✔ 관리자 권한이 있습니다."; + readonly ru: "✔ У вас есть права администратора."; + readonly zh: "✔ 您拥有管理员权限"; + }; + readonly "obsidianLiveSyncSettingTab.okCorsCredentials": { + readonly def: "✔ cors.credentials is ok."; + readonly es: "✔ cors.credentials está correcto."; + readonly fr: "✔ cors.credentials est correct."; + readonly he: "✔ cors.credentials תקין."; + readonly ja: "✔ cors.credentialsは正常です。"; + readonly ko: "✔ cors.credentials가 정상입니다."; + readonly ru: "✔ cors.credentials в порядке."; + readonly zh: "✔ cors.credentials 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": { + readonly def: "CORS credentials OK"; + readonly es: "CORS credenciales OK"; + readonly fr: "Identifiants CORS OK"; + readonly he: "CORS credentials תקין"; + readonly ja: "CORS認証情報OK"; + readonly ko: "CORS 자격 증명 정상"; + readonly ru: "CORS учётные данные в порядке"; + readonly zh: "CORS 凭据正常"; + }; + readonly "obsidianLiveSyncSettingTab.okCorsOriginMatched": { + readonly def: "✔ CORS origin OK"; + readonly es: "✔ Origen de CORS correcto"; + readonly fr: "✔ Origine CORS OK"; + readonly he: "✔ CORS origin תקין"; + readonly ja: "✔ CORSオリジンOK"; + readonly ko: "✔ CORS 원점 정상"; + readonly ru: "✔ CORS origin в порядке"; + readonly zh: "✔ CORS 源正常"; + }; + readonly "obsidianLiveSyncSettingTab.okCorsOrigins": { + readonly def: "✔ cors.origins is ok."; + readonly es: "✔ cors.origins está correcto."; + readonly fr: "✔ cors.origins est correct."; + readonly he: "✔ cors.origins תקין."; + readonly ja: "✔ cors.originsは正常です。"; + readonly ko: "✔ cors.origins가 정상입니다."; + readonly ru: "✔ cors.origins в порядке."; + readonly zh: "✔ cors.origins 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okEnableCors": { + readonly def: "✔ httpd.enable_cors is ok."; + readonly es: "✔ httpd.enable_cors está correcto."; + readonly fr: "✔ httpd.enable_cors est correct."; + readonly he: "✔ httpd.enable_cors תקין."; + readonly ja: "✔ httpd.enable_corsは正常です。"; + readonly ko: "✔ httpd.enable_cors가 정상입니다."; + readonly ru: "✔ httpd.enable_cors в порядке."; + readonly zh: "✔ httpd.enable_cors 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okEnableCorsChttpd": { + readonly def: "✔ chttpd.enable_cors is ok."; + readonly fr: "✔ chttpd.enable_cors est correct."; + readonly he: "✔ chttpd.enable_cors תקין."; + readonly ja: "✔ chttpd.enable_corsは正常です。"; + readonly ru: "✔ chttpd.enable_cors в порядке."; + readonly zh: "✔ chttpd.enable_cors is ok."; + }; + readonly "obsidianLiveSyncSettingTab.okMaxDocumentSize": { + readonly def: "✔ couchdb.max_document_size is ok."; + readonly es: "✔ couchdb.max_document_size está correcto."; + readonly fr: "✔ couchdb.max_document_size est correct."; + readonly he: "✔ couchdb.max_document_size תקין."; + readonly ja: "✔ couchdb.max_document_sizeは正常です。"; + readonly ko: "✔ couchdb.max_document_size가 정상입니다."; + readonly ru: "✔ couchdb.max_document_size в порядке."; + readonly zh: "✔ couchdb.max_document_size 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okMaxRequestSize": { + readonly def: "✔ chttpd.max_http_request_size is ok."; + readonly es: "✔ chttpd.max_http_request_size está correcto."; + readonly fr: "✔ chttpd.max_http_request_size est correct."; + readonly he: "✔ chttpd.max_http_request_size תקין."; + readonly ja: "✔ chttpd.max_http_request_sizeは正常です。"; + readonly ko: "✔ chttpd.max_http_request_size가 정상입니다."; + readonly ru: "✔ chttpd.max_http_request_size в порядке."; + readonly zh: "✔ chttpd.max_http_request_size 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okRequireValidUser": { + readonly def: "✔ chttpd.require_valid_user is ok."; + readonly es: "✔ chttpd.require_valid_user está correcto."; + readonly fr: "✔ chttpd.require_valid_user est correct."; + readonly he: "✔ chttpd.require_valid_user תקין."; + readonly ja: "✔ chttpd.require_valid_userは正常です。"; + readonly ko: "✔ chttpd.require_valid_user가 정상입니다."; + readonly ru: "✔ chttpd.require_valid_user в порядке."; + readonly zh: "✔ chttpd.require_valid_user 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okRequireValidUserAuth": { + readonly def: "✔ chttpd_auth.require_valid_user is ok."; + readonly es: "✔ chttpd_auth.require_valid_user está correcto."; + readonly fr: "✔ chttpd_auth.require_valid_user est correct."; + readonly he: "✔ chttpd_auth.require_valid_user תקין."; + readonly ja: "✔ chttpd_auth.require_valid_userは正常です。"; + readonly ko: "✔ chttpd_auth.require_valid_user가 정상입니다."; + readonly ru: "✔ chttpd_auth.require_valid_user в порядке."; + readonly zh: "✔ chttpd_auth.require_valid_user 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.okWwwAuth": { + readonly def: "✔ httpd.WWW-Authenticate is ok."; + readonly es: "✔ httpd.WWW-Authenticate está correcto."; + readonly fr: "✔ httpd.WWW-Authenticate est correct."; + readonly he: "✔ httpd.WWW-Authenticate תקין."; + readonly ja: "✔ httpd.WWW-Authenticateは正常です。"; + readonly ko: "✔ httpd.WWW-Authenticate가 정상입니다."; + readonly ru: "✔ httpd.WWW-Authenticate в порядке."; + readonly zh: "✔ httpd.WWW-Authenticate 设置正确"; + }; + readonly "obsidianLiveSyncSettingTab.optionApply": { + readonly def: "Apply"; + readonly es: "Aplicar"; + readonly fr: "Appliquer"; + readonly he: "החל"; + readonly ja: "適用"; + readonly ko: "적용"; + readonly ru: "Применить"; + readonly zh: "应用"; + }; + readonly "obsidianLiveSyncSettingTab.optionCancel": { + readonly def: "Cancel"; + readonly es: "Cancelar"; + readonly fr: "Annuler"; + readonly he: "ביטול"; + readonly ja: "キャンセル"; + readonly ko: "취소"; + readonly ru: "Отмена"; + readonly zh: "取消"; + }; + readonly "obsidianLiveSyncSettingTab.optionCouchDB": { + readonly def: "CouchDB"; + readonly es: "CouchDB"; + readonly fr: "CouchDB"; + readonly he: "CouchDB"; + readonly ja: "CouchDB"; + readonly ko: "CouchDB"; + readonly ru: "CouchDB"; + readonly zh: "CouchDB"; + }; + readonly "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": { + readonly def: "Disable all automatic"; + readonly es: "Desactivar lo automático"; + readonly fr: "Désactiver toute automatisation"; + readonly he: "נטרל את כל האוטומטי"; + readonly ja: "すべての自動を無効化"; + readonly ko: "모든 자동 비활성화"; + readonly ru: "Отключить всё автоматическое"; + readonly zh: "禁用所有自动同步"; + readonly "zh-tw": "停用所有自動同步"; + }; + readonly "obsidianLiveSyncSettingTab.optionFetchFromRemote": { + readonly def: "Fetch from Remote"; + readonly es: "Obtener del remoto"; + readonly fr: "Récupérer depuis le distant"; + readonly he: "משוך מהשרת המרוחד"; + readonly ja: "リモートからフェッチ"; + readonly ko: "원격에서 가져오기"; + readonly ru: "Загрузить с удалённого"; + readonly zh: "从远程获取"; + }; + readonly "obsidianLiveSyncSettingTab.optionHere": { + readonly def: "HERE"; + readonly es: "AQUÍ"; + readonly fr: "ICI"; + readonly he: "כאן"; + readonly ja: "ここ"; + readonly ko: "여기"; + readonly ru: "ЗДЕСЬ"; + readonly zh: "这里"; + }; + readonly "obsidianLiveSyncSettingTab.optionLiveSync": { + readonly def: "LiveSync"; + readonly es: "Sincronización LiveSync"; + readonly fr: "LiveSync"; + readonly he: "LiveSync"; + readonly ja: "LiveSync 同期"; + readonly ko: "LiveSync 동기화"; + readonly ru: "Синхронизация LiveSync"; + readonly zh: "LiveSync 同步"; + readonly "zh-tw": "LiveSync 同步"; + }; + readonly "obsidianLiveSyncSettingTab.optionMinioS3R2": { + readonly def: "Minio,S3,R2"; + readonly es: "Minio,S3,R2"; + readonly fr: "Minio, S3, R2"; + readonly he: "Minio,S3,R2"; + readonly ja: "Minio,S3,R2"; + readonly ko: "Minio,S3,R2"; + readonly ru: "Minio,S3,R2"; + readonly zh: "Minio, S3, R2"; + }; + readonly "obsidianLiveSyncSettingTab.optionOkReadEverything": { + readonly def: "OK, I have read everything."; + readonly es: "OK, he leído todo."; + readonly fr: "OK, j'ai tout lu."; + readonly he: "בסדר, קראתי הכל."; + readonly ja: "OK、すべて読みました。"; + readonly ko: "네, 모든 것을 읽었습니다."; + readonly ru: "ОК, я всё прочитал."; + readonly zh: "好的,我已经阅读了所有内容 "; + }; + readonly "obsidianLiveSyncSettingTab.optionOnEvents": { + readonly def: "On events"; + readonly es: "En eventos"; + readonly fr: "Sur événements"; + readonly he: "על אירועים"; + readonly ja: "イベント時"; + readonly ko: "이벤트 시"; + readonly ru: "По событиям"; + readonly zh: "事件触发时"; + readonly "zh-tw": "事件觸發時"; + }; + readonly "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": { + readonly def: "Periodic and on events"; + readonly es: "Periódico y en eventos"; + readonly fr: "Périodique et sur événements"; + readonly he: "תקופתי ועל אירועים"; + readonly ja: "定期およびイベント時"; + readonly ko: "주기적 및 이벤트 시"; + readonly ru: "Периодически и по событиям"; + readonly zh: "定期与事件触发"; + readonly "zh-tw": "定期與事件觸發"; + }; + readonly "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": { + readonly def: "Periodic w/ batch"; + readonly es: "Periódico con lote"; + readonly fr: "Périodique avec lot"; + readonly he: "תקופתי עם אצווה"; + readonly ja: "バッチ付き定期"; + readonly ko: "주기적 w/ 일괄"; + readonly ru: "Периодически с пакетами"; + readonly zh: "定期(批处理)"; + readonly "zh-tw": "定期(批次)"; + }; + readonly "obsidianLiveSyncSettingTab.optionRebuildBoth": { + readonly def: "Rebuild Both from This Device"; + readonly es: "Reconstructuir ambos desde este dispositivo"; + readonly fr: "Tout reconstruire depuis cet appareil"; + readonly he: "בנה שניהם מחדש ממכשיר זה"; + readonly ja: "このデバイスから両方を再構築"; + readonly ko: "이 기기에서 둘 다 재구축"; + readonly ru: "Перестроить оба с этого устройства"; + readonly zh: "从此设备重建两者"; + }; + readonly "obsidianLiveSyncSettingTab.optionSaveOnlySettings": { + readonly def: "(Danger) Save Only Settings"; + readonly es: "(Peligro) Guardar solo configuración"; + readonly fr: "(Danger) N'enregistrer que les paramètres"; + readonly he: "(סכנה) שמור הגדרות בלבד"; + readonly ja: "(危険) 設定のみ保存"; + readonly ko: "(위험) 설정만 저장"; + readonly ru: "(Опасно) Сохранить только настройки"; + readonly zh: "(危险)仅保存设置"; + }; + readonly "obsidianLiveSyncSettingTab.panelChangeLog": { + readonly def: "Change Log"; + readonly es: "Registro de cambios"; + readonly fr: "Journal des modifications"; + readonly he: "יומן שינויים"; + readonly ja: "変更履歴"; + readonly ko: "변경 로그"; + readonly ru: "История изменений"; + readonly zh: "更新日志"; + }; + readonly "obsidianLiveSyncSettingTab.panelGeneralSettings": { + readonly def: "General Settings"; + readonly es: "Configuraciones Generales"; + readonly fr: "Paramètres généraux"; + readonly he: "הגדרות כלליות"; + readonly ja: "一般設定"; + readonly ko: "일반 설정"; + readonly ru: "Основные настройки"; + readonly zh: "常规设置"; + }; + readonly "obsidianLiveSyncSettingTab.panelPrivacyEncryption": { + readonly def: "Privacy & Encryption"; + readonly es: "Privacidad y Cifrado"; + readonly fr: "Confidentialité et chiffrement"; + readonly he: "פרטיות והצפנה"; + readonly ja: "プライバシーと暗号化"; + readonly ko: "개인정보 보호 및 암호화"; + readonly ru: "Конфиденциальность и шифрование"; + readonly zh: "隐私与加密"; + }; + readonly "obsidianLiveSyncSettingTab.panelRemoteConfiguration": { + readonly def: "Remote Configuration"; + readonly es: "Configuración remota"; + readonly fr: "Configuration distante"; + readonly he: "תצורת שרת מרוחד"; + readonly ja: "リモート設定"; + readonly ko: "원격 구성"; + readonly ru: "Удалённая конфигурация"; + readonly zh: "远程配置"; + }; + readonly "obsidianLiveSyncSettingTab.panelSetup": { + readonly def: "Setup"; + readonly es: "Configuración"; + readonly fr: "Configuration"; + readonly he: "הגדרה"; + readonly ja: "セットアップ"; + readonly ko: "설정"; + readonly ru: "Настройка"; + readonly zh: "设置"; + }; + readonly "obsidianLiveSyncSettingTab.serverVersion": { + readonly def: "Server info: ${info}"; + readonly fr: "Infos serveur : ${info}"; + readonly he: "פרטי שרת: ${info}"; + readonly ja: "サーバー情報: ${info}"; + readonly ru: "Информация о сервере: info"; + readonly zh: "服务器信息: ${info}"; + }; + readonly "obsidianLiveSyncSettingTab.titleActiveRemoteServer": { + readonly def: "Active Remote Server"; + readonly fr: "Serveur distant actif"; + readonly he: "שרת מרוחד פעיל"; + readonly ja: "アクティブなリモートサーバー"; + readonly ru: "Активный удалённый сервер"; + readonly zh: "活动远程服务器"; + }; + readonly "obsidianLiveSyncSettingTab.titleAppearance": { + readonly def: "Appearance"; + readonly es: "Apariencia"; + readonly fr: "Apparence"; + readonly he: "מראה"; + readonly ja: "外観"; + readonly ko: "외관"; + readonly ru: "Внешний вид"; + readonly zh: "外观"; + readonly "zh-tw": "外觀"; + }; + readonly "obsidianLiveSyncSettingTab.titleConflictResolution": { + readonly def: "Conflict resolution"; + readonly es: "Resolución de conflictos"; + readonly fr: "Résolution des conflits"; + readonly he: "פתרון קונפליקטים"; + readonly ja: "競合解決"; + readonly ko: "충돌 해결"; + readonly ru: "Разрешение конфликтов"; + readonly zh: "冲突处理"; + readonly "zh-tw": "衝突處理"; + }; + readonly "obsidianLiveSyncSettingTab.titleCongratulations": { + readonly def: "Congratulations!"; + readonly es: "¡Felicidades!"; + readonly fr: "Félicitations !"; + readonly he: "מזל טוב!"; + readonly ja: "おめでとうございます!"; + readonly ko: "축하합니다!"; + readonly ru: "Поздравляем!"; + readonly zh: "恭喜!"; + readonly "zh-tw": "恭喜!"; + }; + readonly "obsidianLiveSyncSettingTab.titleCouchDB": { + readonly def: "CouchDB"; + readonly es: "Servidor CouchDB"; + readonly fr: "CouchDB"; + readonly he: "CouchDB"; + readonly ja: "CouchDB サーバー"; + readonly ko: "CouchDB 서버"; + readonly ru: "Сервер CouchDB"; + readonly zh: "CouchDB 服务器"; + readonly "zh-tw": "CouchDB 伺服器"; + }; + readonly "obsidianLiveSyncSettingTab.titleDeletionPropagation": { + readonly def: "Deletion Propagation"; + readonly es: "Propagación de eliminación"; + readonly fr: "Propagation des suppressions"; + readonly he: "הפצת מחיקות"; + readonly ja: "削除の伝播"; + readonly ko: "삭제 전파"; + readonly ru: "Распространение удалений"; + readonly zh: "删除传播"; + readonly "zh-tw": "刪除傳播"; + }; + readonly "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": { + readonly def: "Encryption is not enabled"; + readonly es: "El cifrado no está habilitado"; + readonly fr: "Le chiffrement n'est pas activé"; + readonly he: "ההצפנה אינה מופעלת"; + readonly ja: "暗号化が有効になっていません"; + readonly ko: "암호화가 활성화되지 않음"; + readonly ru: "Шифрование не включено"; + readonly zh: "尚未启用加密"; + readonly "zh-tw": "尚未啟用加密"; + }; + readonly "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": { + readonly def: "Encryption Passphrase Invalid"; + readonly es: "La frase de contraseña de cifrado es inválida"; + readonly fr: "Phrase secrète de chiffrement invalide"; + readonly he: "ביטוי סיסמה להצפנה לא תקין"; + readonly ja: "暗号化パスフレーズが無効です"; + readonly ko: "암호화 패스프레이즈 유효하지 않음"; + readonly ru: "Парольная фраза шифрования недействительна"; + readonly zh: "加密密码短语无效"; + readonly "zh-tw": "加密密語無效"; + }; + readonly "obsidianLiveSyncSettingTab.titleExtraFeatures": { + readonly def: "Enable extra and advanced features"; + readonly es: "Habilitar funciones extras y avanzadas"; + readonly fr: "Activer les fonctionnalités supplémentaires et avancées"; + readonly he: "הפעל תכונות נוספות ומתקדמות"; + readonly ja: "追加および上級機能を有効化"; + readonly ko: "추가 및 고급 기능 활성화"; + readonly ru: "Включить дополнительные и расширенные функции"; + readonly zh: "启用额外和高级功能"; + }; + readonly "obsidianLiveSyncSettingTab.titleFetchConfig": { + readonly def: "Fetch Config"; + readonly es: "Obtener configuración"; + readonly fr: "Récupérer la configuration"; + readonly he: "משוך תצורה"; + readonly ja: "設定を取得"; + readonly ko: "구성 가져오기"; + readonly ru: "Загрузить конфигурацию"; + readonly zh: "获取配置"; + readonly "zh-tw": "抓取設定"; + }; + readonly "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": { + readonly def: "Fetch config from remote server"; + readonly es: "Obtener configuración del servidor remoto"; + readonly fr: "Récupérer la configuration depuis le serveur distant"; + readonly he: "משוך תצורה מהשרת המרוחד"; + readonly ja: "リモートサーバーから設定を取得"; + readonly ko: "원격 서버에서 구성 가져오기"; + readonly ru: "Загрузить конфигурацию с удалённого сервера"; + readonly zh: "从远程服务器获取配置"; + }; + readonly "obsidianLiveSyncSettingTab.titleFetchSettings": { + readonly def: "Fetch Settings"; + readonly es: "Obtener configuraciones"; + readonly fr: "Récupérer les paramètres"; + readonly he: "משוך הגדרות"; + readonly ja: "設定の取得"; + readonly ko: "설정 가져오기"; + readonly ru: "Загрузить настройки"; + readonly zh: "获取设置"; + }; + readonly "obsidianLiveSyncSettingTab.titleHiddenFiles": { + readonly def: "Hidden Files"; + readonly es: "Archivos ocultos"; + readonly fr: "Fichiers cachés"; + readonly he: "קבצים נסתרים"; + readonly ja: "隠しファイル"; + readonly ko: "숨김 파일"; + readonly ru: "Скрытые файлы"; + readonly zh: "隐藏文件"; + readonly "zh-tw": "隱藏檔案"; + }; + readonly "obsidianLiveSyncSettingTab.titleLogging": { + readonly def: "Logging"; + readonly es: "Registro"; + readonly fr: "Journalisation"; + readonly he: "רישום יומן"; + readonly ja: "ログ"; + readonly ko: "로깅"; + readonly ru: "Логирование"; + readonly zh: "日志"; + readonly "zh-tw": "記錄"; + }; + readonly "obsidianLiveSyncSettingTab.titleMinioS3R2": { + readonly def: "Minio,S3,R2"; + readonly es: "MinIO, S3, R2"; + readonly fr: "Minio, S3, R2"; + readonly he: "Minio,S3,R2"; + readonly ja: "MinIO、S3、R2"; + readonly ko: "MinIO, S3, R2"; + readonly ru: "MinIO, S3, R2"; + readonly zh: "MinIO、S3、R2"; + readonly "zh-tw": "MinIO、S3、R2"; + }; + readonly "obsidianLiveSyncSettingTab.titleNotification": { + readonly def: "Notification"; + readonly es: "Notificación"; + readonly fr: "Notification"; + readonly he: "התראה"; + readonly ja: "通知"; + readonly ko: "알림"; + readonly ru: "Уведомления"; + readonly zh: "通知"; + readonly "zh-tw": "通知"; + }; + readonly "obsidianLiveSyncSettingTab.titleOnlineTips": { + readonly def: "Online Tips"; + readonly es: "Consejos en línea"; + readonly fr: "Conseils en ligne"; + readonly he: "טיפים אונליין"; + readonly ja: "オンラインヒント"; + readonly ko: "온라인 팁"; + readonly ru: "Онлайн советы"; + readonly zh: "在线提示"; + }; + readonly "obsidianLiveSyncSettingTab.titleQuickSetup": { + readonly def: "Quick Setup"; + readonly es: "Configuración rápida"; + readonly fr: "Configuration rapide"; + readonly he: "הגדרה מהירה"; + readonly ja: "クイックセットアップ"; + readonly ko: "빠른 설정"; + readonly ru: "Быстрая настройка"; + readonly zh: "快速设置"; + }; + readonly "obsidianLiveSyncSettingTab.titleRebuildRequired": { + readonly def: "Rebuild Required"; + readonly es: "Reconstrucción necesaria"; + readonly fr: "Reconstruction requise"; + readonly he: "נדרשת בנייה מחדש"; + readonly ja: "再構築が必要"; + readonly ko: "재구축 필요"; + readonly ru: "Требуется перестроение"; + readonly zh: "需要重建"; + }; + readonly "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": { + readonly def: "Remote Configuration Check Failed"; + readonly es: "La verificación de configuración remota falló"; + readonly fr: "Échec de la vérification de la configuration distante"; + readonly he: "בדיקת תצורת שרת מרוחד נכשלה"; + readonly ja: "リモート設定の確認に失敗"; + readonly ko: "원격 구성 확인 실패"; + readonly ru: "Проверка удалённой конфигурации не удалась"; + readonly zh: "远端配置检查失败"; + readonly "zh-tw": "遠端設定檢查失敗"; + }; + readonly "obsidianLiveSyncSettingTab.titleRemoteServer": { + readonly def: "Remote Server"; + readonly es: "Servidor remoto"; + readonly fr: "Serveur distant"; + readonly he: "שרת מרוחד"; + readonly ja: "リモートサーバー"; + readonly ko: "원격 서버"; + readonly ru: "Удалённый сервер"; + readonly zh: "远端服务器"; + readonly "zh-tw": "遠端伺服器"; + }; + readonly "obsidianLiveSyncSettingTab.titleReset": { + readonly def: "Reset"; + readonly es: "Reiniciar"; + readonly fr: "Réinitialiser"; + readonly he: "אתחול"; + readonly ja: "リセット"; + readonly ko: "리셋"; + readonly ru: "Сброс"; + readonly zh: "重置"; + }; + readonly "obsidianLiveSyncSettingTab.titleSetupOtherDevices": { + readonly def: "To setup other devices"; + readonly es: "Para configurar otros dispositivos"; + readonly fr: "Pour configurer d'autres appareils"; + readonly he: "להגדרת מכשירים אחרים"; + readonly ja: "他のデバイスのセットアップ"; + readonly ko: "다른 기기 설정"; + readonly ru: "Для настройки других устройств"; + readonly zh: "设置其他设备"; + }; + readonly "obsidianLiveSyncSettingTab.titleSynchronizationMethod": { + readonly def: "Synchronization Method"; + readonly es: "Método de sincronización"; + readonly fr: "Méthode de synchronisation"; + readonly he: "שיטת סנכרון"; + readonly ja: "同期方法"; + readonly ko: "동기화 방법"; + readonly ru: "Метод синхронизации"; + readonly zh: "同步方式"; + readonly "zh-tw": "同步方式"; + }; + readonly "obsidianLiveSyncSettingTab.titleSynchronizationPreset": { + readonly def: "Synchronization Preset"; + readonly es: "Preestablecimiento de sincronización"; + readonly fr: "Préréglage de synchronisation"; + readonly he: "קבוע מראש לסנכרון"; + readonly ja: "同期プリセット"; + readonly ko: "동기화 프리셋"; + readonly ru: "Пресет синхронизации"; + readonly zh: "同步预设"; + readonly "zh-tw": "同步預設"; + }; + readonly "obsidianLiveSyncSettingTab.titleSyncSettings": { + readonly def: "Sync Settings"; + readonly es: "Configuraciones de Sincronización"; + readonly fr: "Paramètres de synchronisation"; + readonly he: "הגדרות סנכרון"; + readonly ja: "同期設定"; + readonly ko: "동기화 설정"; + readonly ru: "Настройки синхронизации"; + readonly zh: "同步设置"; + }; + readonly "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": { + readonly def: "Sync Settings via Markdown"; + readonly es: "Configuración de sincronización a través de Markdown"; + readonly fr: "Synchroniser les paramètres via Markdown"; + readonly he: "סנכרון הגדרות דרך Markdown"; + readonly ja: "Markdown経由で設定を同期"; + readonly ko: "마크다운을 통한 동기화 설정"; + readonly ru: "Синхронизация настроек через Markdown"; + readonly zh: "通过 Markdown 同步设置"; + readonly "zh-tw": "透過 Markdown 同步設定"; + }; + readonly "obsidianLiveSyncSettingTab.titleUpdateThinning": { + readonly def: "Update Thinning"; + readonly es: "Actualización de adelgazamiento"; + readonly fr: "Lissage des mises à jour"; + readonly he: "דילול עדכונים"; + readonly ja: "更新の間引き"; + readonly ko: "업데이트 솎아내기"; + readonly ru: "Оптимизация обновлений"; + readonly zh: "更新精简"; + readonly "zh-tw": "更新精簡"; + }; + readonly "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": { + readonly def: "⚠ CORS Origin is unmatched ${from}->${to}"; + readonly es: "⚠ El origen de CORS no coincide: {from}->{to}"; + readonly fr: "⚠ L'origine CORS ne correspond pas ${from}->${to}"; + readonly he: "⚠ CORS Origin אינו תואם ${from}->${to}"; + readonly ja: "⚠ CORS Originが一致しません ${from}->${to}"; + readonly ko: "⚠ CORS 원점이 일치하지 않습니다 {from}->{to}"; + readonly ru: "⚠ CORS Origin не совпадает from->to"; + readonly zh: "⚠ CORS 源不匹配 {from}->{to}"; + }; + readonly "obsidianLiveSyncSettingTab.warnNoAdmin": { + readonly def: "⚠ You do not have administrator privileges."; + readonly es: "⚠ No tienes privilegios de administrador."; + readonly fr: "⚠ Vous n'avez pas les privilèges administrateur."; + readonly he: "⚠ אין לך הרשאות מנהל."; + readonly ja: "⚠ 管理者権限がありません。"; + readonly ko: "⚠ 관리자 권한이 없습니다."; + readonly ru: "⚠ У вас нет прав администратора."; + readonly zh: "⚠ 您没有管理员权限"; + }; + readonly Ok: { + readonly def: "Ok"; + readonly es: "Aceptar"; + readonly ja: "OK"; + readonly ko: "확인"; + readonly ru: "ОК"; + readonly zh: "确定"; + readonly "zh-tw": "確定"; + }; + readonly "Old Algorithm": { + readonly def: "Old Algorithm"; + readonly es: "Algoritmo antiguo"; + readonly ja: "旧アルゴリズム"; + readonly ko: "이전 알고리즘"; + readonly ru: "Старый алгоритм"; + readonly zh: "旧算法"; + readonly "zh-tw": "舊演算法"; + }; + readonly "Older fallback (Slow, W/O WebAssembly)": { + readonly def: "Older fallback (Slow, W/O WebAssembly)"; + readonly es: "Alternativa anterior (lenta, sin WebAssembly)"; + readonly ja: "旧フォールバック (低速、WebAssembly なし)"; + readonly ko: "이전 대체 방식 (느림, WebAssembly 없음)"; + readonly ru: "Старый вариант fallback (медленный, без WebAssembly)"; + readonly zh: "旧版回退(较慢,无 WebAssembly)"; + readonly "zh-tw": "舊版回退(較慢,無 WebAssembly)"; + }; + readonly Open: { + readonly def: "Open"; + readonly es: "Abrir"; + readonly ja: "開く"; + readonly ko: "열기"; + readonly ru: "Открыть"; + readonly zh: "打开"; + }; + readonly "Open the dialog": { + readonly def: "Open the dialog"; + readonly es: "Abrir el diálogo"; + readonly ja: "ダイアログを開く"; + readonly ko: "대화상자 열기"; + readonly ru: "Открыть диалог"; + readonly zh: "打开对话框"; + }; + readonly Overwrite: { + readonly def: "Overwrite"; + readonly es: "Sobrescribir"; + readonly ja: "上書き"; + readonly ko: "덮어쓰기"; + readonly ru: "Перезаписать"; + readonly zh: "覆盖"; + }; + readonly "Overwrite patterns": { + readonly def: "Overwrite patterns"; + readonly es: "Patrones de sobrescritura"; + readonly ja: "上書きパターン"; + readonly ko: "덮어쓰기 패턴"; + readonly ru: "Шаблоны перезаписи"; + readonly zh: "覆盖模式"; + readonly "zh-tw": "覆寫模式"; + }; + readonly "Overwrite remote": { + readonly def: "Overwrite remote"; + readonly es: "Sobrescribir remoto"; + readonly ja: "リモートを上書き"; + readonly ko: "원격 덮어쓰기"; + readonly ru: "Перезаписать удалённое хранилище"; + readonly zh: "覆盖远端"; + readonly "zh-tw": "覆寫遠端"; + }; + readonly "Overwrite remote with local DB and passphrase.": { + readonly def: "Overwrite remote with local DB and passphrase."; + readonly es: "Sobrescribe el remoto con la base de datos local y la frase de contraseña."; + readonly ja: "ローカル DB とパスフレーズでリモートを上書きします。"; + readonly ko: "로컬 DB와 암호문구로 원격을 덮어씁니다."; + readonly ru: "Перезаписать удалённое хранилище локальной БД и парольной фразой."; + readonly zh: "使用本地数据库和密码短语覆盖远端。"; + readonly "zh-tw": "使用本機資料庫與密語覆寫遠端。"; + }; + readonly "Overwrite Server Data with This Device's Files": { + readonly def: "Overwrite Server Data with This Device's Files"; + readonly es: "Sobrescribir los datos del servidor con los archivos de este dispositivo"; + readonly ja: "このデバイスのファイルでサーバーデータを上書き"; + readonly ko: "이 기기의 파일로 서버 데이터를 덮어쓰기"; + readonly ru: "Перезаписать данные сервера файлами с этого устройства"; + readonly zh: "用本设备文件覆盖服务器数据"; + readonly "zh-tw": "以此裝置的檔案覆寫伺服器資料"; + }; + readonly "P2P.AskPassphraseForDecrypt": { + readonly def: "The remote peer shared the configuration. Please input the passphrase to decrypt the configuration."; + readonly fr: "Le pair distant a partagé la configuration. Veuillez saisir la phrase secrète pour déchiffrer la configuration."; + readonly he: "העמית המרוחד שיתף את התצורה. אנא הזן את ביטוי הסיסמה לפענוח התצורה."; + readonly ja: "リモートピアから設定が共有されました。設定を復号するためのパスフレーズを入力してください。"; + readonly ko: "원격 피어가 구성을 공유했습니다. 구성을 복호화하려면 패스프레이즈를 입력해 주세요."; + readonly ru: "Удалённое устройство предоставило конфигурацию. Введите пароль для расшифровки."; + readonly zh: "远程对等方共享了配置,请输入密码短语以解密配置"; + }; + readonly "P2P.AskPassphraseForShare": { + readonly def: "The remote peer requested this device configuration. Please input the passphrase to share the configuration. You can ignore the request by cancelling this dialogue."; + readonly fr: "Le pair distant a demandé la configuration de cet appareil. Veuillez saisir la phrase secrète pour partager la configuration. Vous pouvez ignorer la demande en annulant cette boîte de dialogue."; + readonly he: "העמית המרוחד ביקש את תצורת מכשיר זה. אנא הזן את ביטוי הסיסמה לשיתוף התצורה. ניתן להתעלם מהבקשה על ידי ביטול הדיאלוג."; + readonly ja: "リモートピアからこのデバイスの設定が要求されました。設定を共有するためのパスフレーズを入力してください。このダイアログをキャンセルすることでリクエストを無視できます。"; + readonly ko: "원격 피어가 이 기기의 구성을 요청했습니다. 구성을 공유하려면 패스프레이즈를 입력해 주세요. 이 대화상자를 취소하여 요청을 무시할 수 있습니다."; + readonly ru: "Удалённое устройство запрашивает эту конфигурацию. Введите пароль для передачи."; + readonly zh: "远程对等方请求此设备配置,请输入密码短语以共享配置。你可以通过取消此对话框来忽略此请求"; + }; + readonly "P2P.DisabledButNeed": { + readonly def: "Peer-to-Peer Sync is disabled. Do you really want to enable it?"; + readonly fr: "Synchronisation pair-à-pair est désactivé. Voulez-vous vraiment l'activer ?"; + readonly he: "%{title_p2p_sync} מנוטרל. האם אתה בטוח שברצונך להפעיל?"; + readonly ja: "Peer-to-Peer Syncは無効になっています。本当に有効にしますか?"; + readonly ko: "피어 투 피어(P2P) 동기화가 비활성화되어 있습니다. 정말로 활성화하시겠습니까?"; + readonly ru: "title_p2p_sync отключён. Вы действительно хотите включить?"; + readonly zh: "Peer-to-Peer同步 已禁用。你确定要启用它吗?"; + }; + readonly "P2P.FailedToOpen": { + readonly def: "Failed to open P2P connection to the signalling server."; + readonly fr: "Échec d'ouverture de la connexion P2P vers le serveur de signalisation."; + readonly he: "לא ניתן לפתוח חיבור P2P לשרת האותות."; + readonly ja: "シグナリングサーバーへのP2P接続を開けませんでした。"; + readonly ko: "시그널링 서버에 P2P 연결을 열 수 없습니다."; + readonly ru: "Не удалось открыть P2P подключение к серверу сигнализации."; + readonly zh: "无法打开 P2P 连接到信令服务器"; + }; + readonly "P2P.NoAutoSyncPeers": { + readonly def: "No auto-sync peers found. Please set peers on the Peer-to-Peer Sync pane."; + readonly fr: "Aucun pair de synchronisation automatique trouvé. Veuillez définir des pairs dans le panneau Synchronisation pair-à-pair."; + readonly he: "לא נמצאו עמיתים לסנכרון אוטומטי. אנא הגדר עמיתים בלוח %{long_p2p_sync}."; + readonly ja: "自動同期ピアが見つかりません。Peer-to-Peer Sync (試験機能)ペインでピアを設定してください。"; + readonly ko: "자동 동기화 피어를 찾을 수 없습니다. 피어 투 피어(P2P) 동기화 (실험 기능) 창에서 피어를 설정해 주세요."; + readonly ru: "Автосинхронизируемые устройства не найдены."; + readonly zh: "未找到自动同步的对等方,请在 Peer-to-Peer同步 (实验性) 面板中设置对等方"; + }; + readonly "P2P.NoKnownPeers": { + readonly def: "No peers has been detected, waiting incoming other peers..."; + readonly fr: "Aucun pair détecté, en attente d'autres pairs entrants..."; + readonly he: "לא זוהו עמיתים, ממתין לעמיתים נכנסים..."; + readonly ja: "ピアが検出されていません。他のピアからの接続を待機中..."; + readonly ko: "피어가 감지되지 않았습니다. 다른 피어의 접속을 기다리고 있습니다..."; + readonly ru: "Устройства не обнаружены, ожидаем другие устройства..."; + readonly zh: "未检测到对等方,正在等待其他对等方的连接..."; + }; + readonly "P2P.Note.description": { + readonly def: " This replicator allows us to synchronise our vault with other devices\nusing a peer-to-peer connection. We can use this to synchronise our vault with our other devices without using a cloud service.\nThis replicator is based on Trystero. It also uses a signalling server to establish a connection between devices. The signalling server is used to exchange connection information between devices. It does (or,should) not know or store any of our data.\n\nThe signalling server can be hosted by anyone. This is just a Nostr relay. For the sake of simplicity and checking the behaviour of the replicator, an instance of the signalling server is hosted by vrtmrz. You can use the experimental server provided by vrtmrz, or you can use any other server.\n\nBy the way, even if the signalling server does not store our data, it can see the connection information of some of our devices. Please be aware of this. Also, be cautious when using the server provided by someone else."; + readonly fr: " Ce réplicateur permet de synchroniser notre coffre avec d'autres\nappareils via une connexion pair-à-pair. Nous pouvons l'utiliser pour synchroniser notre coffre avec nos autres appareils sans recourir à un service cloud.\nCe réplicateur est basé sur Trystero. Il utilise également un serveur de signalisation pour établir une connexion entre les appareils. Le serveur de signalisation sert à échanger les informations de connexion entre appareils. Il ne connaît (ou ne devrait connaître) ni ne stocke aucune de nos données.\n\nLe serveur de signalisation peut être hébergé par n'importe qui. Il s'agit simplement d'un relais Nostr. Par souci de simplicité et pour vérifier le comportement du réplicateur, une instance du serveur de signalisation est hébergée par vrtmrz. Vous pouvez utiliser le serveur expérimental fourni par vrtmrz, ou tout autre serveur.\n\nAu passage, même si le serveur de signalisation ne stocke pas nos données, il peut voir les informations de connexion de certains de nos appareils. Soyez-en conscient. Soyez également prudent avec un serveur fourni par quelqu'un d'autre."; + readonly he: " רפליקטור זה מאפשר לסנכרן את הכספת עם מכשירים אחרים באמצעות חיבור עמית-לעמית.\nניתן להשתמש בזה לסנכרון הכספת עם מכשירים אחרים ללא שירות ענן.\nרפליקטור זה מבוסס על Trystero. הוא משתמש גם בשרת אותות לביסוס חיבור בין מכשירים. שרת האותות משמש להחלפת מידע חיבור בין מכשירים. הוא אינו (ולא אמור) לדעת או לאחסן את הנתונים שלנו.\n\nשרת האותות יכול להיות מאוחסן על ידי כל אחד. זהו ממסר Nostr בלבד. לצורך פשטות ובדיקת התנהגות הרפליקטור, vrtmrz מאחסן עותק של שרת האותות. ניתן להשתמש בשרת הניסיוני של vrtmrz, או בכל שרת אחר.\n\nאגב, גם אם שרת האותות אינו מאחסן נתונים, הוא יכול לראות מידע חיבור של חלק ממכשיריך. אנא שים לב לכך. כמו כן, היה זהיר בשימוש בשרת של מישהו אחר."; + readonly ja: "このレプリケーターは、ピアツーピア接続を使用して、Vaultを他のデバイスと同期することができます。クラウドサービスを使用せずに、他のデバイスとVaultを同期することができます。\nこのレプリケーターはTrysteroをベースにしています。デバイス間の接続を確立するためにシグナリングサーバーを使用します。シグナリングサーバーはデバイス間で接続情報を交換するために使用されます。私たちのデータを知ったり保存したりすることはありません(または、そうあるべきではありません)。\n\nシグナリングサーバーは誰でもホストできます。これは単なるNostrリレーです。簡便さとレプリケーターの動作確認のために、vrtmrzがシグナリングサーバーのインスタンスをホストしています。vrtmrzが提供する実験用サーバーを使用することも、他のサーバーを使用することもできます。\n\nなお、シグナリングサーバーが私たちのデータを保存しなくても、一部のデバイスの接続情報を見ることができます。これにご注意ください。また、他の人が提供するサーバーを使用する場合は注意してください。"; + readonly ko: "이 복제기는 피어 투 피어(P2P) 연결을 통해 다른 기기들과 볼트를 동기화할 수 있도록 합니다. 클라우드 서비스를 거치지 않고도 기기간 동기화를 구현할 수 있습니다.\n\n이 복제기는 Trystero를 기반으로 하며, 기기 간 연결을 설정하기 위해 시그널링 서버를 사용합니다. 시그널링 서버는 단순히 연결 정보를 교환하는 용도로만 사용되며, 사용자 데이터를 저장하거나 접근하지 않습니다 (또는 그래야만 합니다).\n\n시그널링 서버는 누구나 운영할 수 있으며, 이는 단순한 Nostr 릴레이입니다. 편의성과 복제기의 작동 확인을 위해 `vrtmrz`가 자체적으로 시그널링 서버 인스턴스를 운영 중입니다. 사용자는 `vrtmrz`가 제공하는 실험용 서버를 사용할 수도 있고, 별도로 자신만의 서버를 설정할 수도 있습니다.\n\n참고로, 시그널링 서버는 사용자 데이터를 저장하지 않더라도 일부 기기의 연결 정보는 볼 수 있습니다. 이 점을 유의해 주세요. 특히 타인이 운영하는 서버를 사용할 경우 주의가 필요합니다."; + readonly ru: "Этот репликатор позволяет синхронизировать хранилище с другими устройствами с использованием однорангового соединения."; + readonly zh: " This replicator allows us to synchronise our vault with other devices\nusing a peer-to-peer connection. We can use this to synchronise our vault with our other devices without using a cloud service.\nThis replicator is based on Trystero. It also uses a signaling server to establish a connection between devices. The signaling server is used to exchange connection information between devices. It does (or,should) not know or store any of our data.\n\nThe signaling server can be hosted by anyone. This is just a Nostr relay. For the sake of simplicity and checking the behaviour of the replicator, an instance of the signaling server is hosted by vrtmrz. You can use the experimental server provided by vrtmrz, or you can use any other server.\n\nBy the way, even if the signaling server does not store our data, it can see the connection information of some of our devices. Please be aware of this. Also, be cautious when using the server provided by someone else."; + }; + readonly "P2P.Note.important_note": { + readonly def: "Peer-to-Peer Replicator."; + readonly fr: "Réplicateur pair-à-pair."; + readonly he: "רפליקטור עמית-לעמית."; + readonly ja: "ピアツーピアレプリケーターの実験的実装"; + readonly ko: "피어 투 피어(P2P) 복제기의 실험적 구현입니다."; + readonly ru: "P2P репликатор."; + readonly zh: "The Experimental Implementation of the Peer-to-Peer Replicator."; + }; + readonly "P2P.Note.important_note_sub": { + readonly def: "This feature is still on the bleeding edge. Please be aware that ensure your data is backed up before using this feature. And, we would be so happy if you could contribute to the development of this feature."; + readonly fr: "Cette fonctionnalité est encore en tout début de développement. Veillez à sauvegarder vos données avant de l'utiliser. Nous serions très heureux si vous contribuiez au développement de cette fonctionnalité."; + readonly he: "תכונה זו עדיין בשלב מתקדם. ודא שהנתונים שלך מגובים לפני השימוש. ונשמח אם תוכל לתרום לפיתוח תכונה זו."; + readonly ja: "この機能はまだ実験段階です。期待通りに動作しない可能性があることにご注意ください。さらに、バグ、セキュリティの問題、その他の問題がある可能性があります。この機能は自己責任でご使用ください。この機能の開発にご協力ください。"; + readonly ko: "이 기능은 아직 실험 단계에 있습니다. 이 기능이 예상대로 작동하지 않을 수 있음을 알아주세요. 또한 버그, 보안 문제 및 기타 문제가 있을 수 있습니다. 이 기능을 사용할 때는 본인의 책임 하에 사용하세요. 이 기능의 개발에 기여해 주세요."; + readonly ru: "Эта функция всё ещё на стадии разработки. Пожалуйста, убедитесь, что ваши данные зарезервированы."; + readonly zh: "This feature is still in the experimental stage. Please be aware that this feature may not work as expected. Furthermore, it may have some bugs, security issues, and other issues. Please use this feature at your own risk. Please contribute to the development of this feature."; + }; + readonly "P2P.Note.Summary": { + readonly def: "What is this feature? (and some important notes, please read once)"; + readonly fr: "Qu'est-ce que cette fonctionnalité ? (et quelques notes importantes, à lire)"; + readonly he: "מהי תכונה זו? (ועוד הערות חשובות, נא לקרוא פעם אחת)"; + readonly ja: "この機能について(重要な注意事項を含む、一度お読みください)"; + readonly ko: "이 기능은 무엇인가요? (설명과 참고사항이 적혀있습니다. 한 번 읽어보세요!)"; + readonly ru: "Что это за функция? (важные замечания)"; + readonly zh: "What is this feature? (and some important notes, please read once)"; + }; + readonly "P2P.NotEnabled": { + readonly def: "Peer-to-Peer Sync is not enabled. We cannot open a new connection."; + readonly fr: "Synchronisation pair-à-pair n'est pas activé. Nous ne pouvons pas ouvrir de nouvelle connexion."; + readonly he: "%{title_p2p_sync} אינו מופעל. לא ניתן לפתוח חיבור חדש."; + readonly ja: "Peer-to-Peer Syncが有効になっていません。新しい接続を開くことができません。"; + readonly ko: "피어 투 피어(P2P) 동기화가 활성화되지 않았습니다. 새로운 연결을 열 수 없습니다."; + readonly ru: "title_p2p_sync не включён. Мы не можем открыть новое подключение."; + readonly zh: "Peer-to-Peer同步 is not enabled. We cannot open a new connection."; + }; + readonly "P2P.P2PReplication": { + readonly def: "Peer-to-Peer Replication"; + readonly fr: "Réplication Pair-à-Pair"; + readonly he: "שכפול %{P2P}"; + readonly ja: "Peer-to-Peerレプリケーション(複製)"; + readonly ko: "피어-to-피어 복제"; + readonly ru: "P2P Репликация"; + readonly zh: "Peer-to-Peer Replication"; + }; + readonly "P2P.PaneTitle": { + readonly def: "Peer-to-Peer Sync"; + readonly fr: "Synchronisation pair-à-pair"; + readonly he: "%{long_p2p_sync}"; + readonly ja: "Peer-to-Peer Sync (試験機能)"; + readonly ko: "피어 투 피어(P2P) 동기화 (실험 기능)"; + readonly ru: "long_p2p_sync"; + readonly zh: "Peer-to-Peer同步 (实验性)"; + }; + readonly "P2P.ReplicatorInstanceMissing": { + readonly def: "P2P Sync replicator is not found, possibly not have been configured or enabled."; + readonly fr: "Le réplicateur Sync P2P est introuvable, peut-être non configuré ou non activé."; + readonly he: "רפליקטור סנכרון P2P לא נמצא, ייתכן שלא הוגדר או הופעל."; + readonly ja: "P2P同期レプリケーターが見つかりません。設定または有効化されていない可能性があります。"; + readonly ko: "P2P 동기화 복제기를 찾을 수 없습니다. 구성되지 않았거나 활성화되지 않았을 수 있습니다."; + readonly ru: "P2P Sync репликатор не найден, возможно, не настроен."; + readonly zh: "P2P Sync replicator is not found, possibly not have been configured or enabled."; + }; + readonly "P2P.SeemsOffline": { + readonly def: "Peer ${name} seems offline, skipped."; + readonly fr: "Le pair ${name} semble hors ligne, ignoré."; + readonly he: "העמית ${name} נראה לא מחובר, מדלג."; + readonly ja: "ピア${name}はオフラインのようです。スキップしました。"; + readonly ko: "피어 ${name}이(가) 오프라인인 것 같습니다. 건너뜁니다."; + readonly ru: "Устройство name офлайн, пропущено."; + readonly zh: "Peer ${name} seems offline, skipped."; + }; + readonly "P2P.SyncAlreadyRunning": { + readonly def: "P2P Sync is already running."; + readonly fr: "La Sync P2P est déjà en cours."; + readonly he: "סנכרון P2P כבר פועל."; + readonly ja: "P2P同期はすでに実行中です。"; + readonly ko: "P2P 동기화가 이미 실행 중입니다."; + readonly ru: "P2P Sync уже запущен."; + readonly zh: "P2P Sync is already running."; + }; + readonly "P2P.SyncCompleted": { + readonly def: "P2P Sync completed."; + readonly fr: "Sync P2P terminée."; + readonly he: "סנכרון P2P הושלם."; + readonly ja: "P2P同期が完了しました。"; + readonly ko: "P2P 동기화가 완료되었습니다."; + readonly ru: "P2P Sync завершён."; + readonly zh: "P2P Sync completed."; + }; + readonly "P2P.SyncStartedWith": { + readonly def: "P2P Sync with ${name} have been started."; + readonly fr: "La Sync P2P avec ${name} a démarré."; + readonly he: "סנכרון P2P עם ${name} התחיל."; + readonly ja: "${name}とのP2P同期を開始しました。"; + readonly ko: "${name}과의 P2P 동기화가 시작되었습니다."; + readonly ru: "P2P Sync с name начат."; + readonly zh: "P2P Sync with ${name} have been started."; + }; + readonly "paneMaintenance.markDeviceResolvedAfterBackup": { + readonly def: "paneMaintenance.markDeviceResolvedAfterBackup"; + readonly es: "Marcar el dispositivo como resuelto después de hacer una copia de seguridad"; + readonly ja: "バックアップ後にこのデバイスを解決済みにする"; + readonly ko: "백업 후 장치를 해결됨으로 표시"; + readonly ru: "Пометить устройство как обработанное после резервного копирования"; + readonly zh: "请在完成备份后将此设备标记为已处理。"; + readonly "zh-tw": "請在完成備份後將此裝置標記為已處理。"; + }; + readonly "paneMaintenance.remoteLockedAndDeviceNotAccepted": { + readonly def: "paneMaintenance.remoteLockedAndDeviceNotAccepted"; + readonly es: "La base de datos remota está bloqueada y este dispositivo aún no ha sido aceptado."; + readonly ja: "リモートデータベースはロックされており、このデバイスはまだ承認されていません。"; + readonly ko: "원격 데이터베이스가 잠겨 있으며 이 장치는 아직 승인되지 않았습니다."; + readonly ru: "Удалённая база данных заблокирована, и это устройство ещё не одобрено."; + readonly zh: "远端数据库已锁定,且此设备尚未被接受。"; + readonly "zh-tw": "遠端資料庫已鎖定,且此裝置尚未被接受。"; + }; + readonly "paneMaintenance.remoteLockedResolvedDevice": { + readonly def: "paneMaintenance.remoteLockedResolvedDevice"; + readonly es: "La base de datos remota está bloqueada, pero este dispositivo ya fue aceptado."; + readonly ja: "リモートデータベースはロックされていますが、このデバイスはすでに承認されています。"; + readonly ko: "원격 데이터베이스가 잠겨 있지만 이 장치는 이미 승인되었습니다."; + readonly ru: "Удалённая база данных заблокирована, но это устройство уже одобрено."; + readonly zh: "远端数据库已锁定,但此设备已被接受。"; + readonly "zh-tw": "遠端資料庫已鎖定,但此裝置已被接受。"; + }; + readonly "paneMaintenance.unlockDatabaseReady": { + readonly def: "paneMaintenance.unlockDatabaseReady"; + readonly es: "Desbloquear la base de datos"; + readonly ja: "データベースのロックを解除"; + readonly ko: "데이터베이스 잠금 해제"; + readonly ru: "Разблокировать базу данных"; + readonly zh: "现在可以解锁数据库。"; + readonly "zh-tw": "現在可以解鎖資料庫。"; + }; + readonly Passphrase: { + readonly def: "Passphrase"; + readonly es: "Frase de contraseña"; + readonly fr: "Phrase secrète"; + readonly he: "ביטוי סיסמה"; + readonly ja: "パスフレーズ"; + readonly ko: "패스프레이즈"; + readonly ru: "Парольная фраза"; + readonly zh: "密码"; + }; + readonly "Passphrase of sensitive configuration items": { + readonly def: "Passphrase of sensitive configuration items"; + readonly es: "Frase para elementos sensibles"; + readonly fr: "Phrase secrète des éléments de configuration sensibles"; + readonly he: "ביטוי סיסמה לפריטי תצורה רגישים"; + readonly ja: "機密性の高い設定項目にパスフレーズを使用"; + readonly ko: "민감한 구성 항목의 패스프레이즈"; + readonly ru: "Парольная фраза для конфиденциальных настроек"; + readonly zh: "敏感配置项的密码"; + }; + readonly password: { + readonly def: "password"; + readonly es: "contraseña"; + readonly fr: "mot de passe"; + readonly he: "סיסמה"; + readonly ja: "パスワード"; + readonly ko: "비밀번호"; + readonly ru: "пароль"; + readonly zh: "密码"; + }; + readonly Password: { + readonly def: "Password"; + readonly es: "Contraseña"; + readonly fr: "Mot de passe"; + readonly he: "סיסמה"; + readonly ja: "パスワード"; + readonly ko: "비밀번호"; + readonly ru: "Пароль"; + readonly zh: "密码"; + }; + readonly "Paste a connection string": { + readonly def: "Paste a connection string"; + readonly es: "Pegar cadena de conexión"; + readonly ja: "接続文字列を貼り付ける"; + readonly ko: "연결 문자열 붙여넣기"; + readonly ru: "Вставить строку подключения"; + readonly zh: "粘贴连接字符串"; + readonly "zh-tw": "貼上連線字串"; + }; + readonly "Paste the Setup URI generated from one of your active devices.": { + readonly def: "Paste the Setup URI generated from one of your active devices."; + readonly es: "Pegue el URI de configuración generado desde uno de sus dispositivos activos。"; + readonly ja: "稼働中の端末で生成した Setup URI を貼り付けてください。"; + readonly ko: "현재 사용 중인 장치 중 하나에서 생성한 설정 URI를 붙여 넣으세요。"; + readonly ru: "Вставьте Setup URI, созданный на одном из ваших активных устройств。"; + readonly zh: "粘贴从一台已在使用的设备上生成的 Setup URI。"; + readonly "zh-tw": "貼上從一台已在使用裝置上產生的 Setup URI。"; + }; + readonly "Path Obfuscation": { + readonly def: "Path Obfuscation"; + readonly es: "Ofuscación de rutas"; + readonly fr: "Obfuscation des chemins"; + readonly he: "ערפול נתיב"; + readonly ja: "パスの難読化"; + readonly ko: "경로 난독화"; + readonly ru: "Обфускация путей"; + readonly zh: "路径混淆"; + }; + readonly "Patterns to match files for overwriting instead of merging": { + readonly def: "Patterns to match files for overwriting instead of merging"; + readonly es: "Patrones para identificar archivos que se sobrescribirán en lugar de fusionarse"; + readonly ja: "マージではなく上書きするファイルを判定するパターン"; + readonly ko: "병합 대신 덮어쓸 파일을 판별하는 패턴"; + readonly ru: "Шаблоны для файлов, которые нужно перезаписывать вместо объединения"; + readonly zh: "用于匹配需覆盖而非合并文件的模式"; + readonly "zh-tw": "用於匹配需覆寫而非合併檔案的模式"; + }; + readonly "Patterns to match files for syncing": { + readonly def: "Patterns to match files for syncing"; + readonly es: "Patrones para identificar archivos que se sincronizarán"; + readonly ja: "同期対象ファイルを判定するパターン"; + readonly ko: "동기화할 파일을 판별하는 패턴"; + readonly ru: "Шаблоны для файлов, которые нужно синхронизировать"; + readonly zh: "用于匹配同步文件的模式"; + readonly "zh-tw": "用於匹配同步檔案的模式"; + }; + readonly "Peer-to-Peer only": { + readonly def: "Peer-to-Peer only"; + readonly es: "Solo Peer-to-Peer"; + readonly ja: "Peer-to-Peer のみ"; + readonly ko: "Peer-to-Peer 전용"; + readonly ru: "Только Peer-to-Peer"; + readonly zh: "仅 Peer-to-Peer"; + readonly "zh-tw": "僅 Peer-to-Peer"; + }; + readonly "Peer-to-Peer Synchronisation": { + readonly def: "Peer-to-Peer Synchronisation"; + readonly es: "Sincronización entre pares"; + readonly ja: "ピアツーピア同期"; + readonly ko: "피어 투 피어 동기화"; + readonly ru: "Одноранговая синхронизация"; + readonly zh: "点对点同步"; + readonly "zh-tw": "點對點同步"; + }; + readonly "Per-file-saved customization sync": { + readonly def: "Per-file-saved customization sync"; + readonly es: "Sincronización de personalización por archivo"; + readonly fr: "Synchronisation de personnalisation enregistrée par fichier"; + readonly he: "סנכרון התאמה אישית שנשמר לפי קובץ"; + readonly ja: "ファイルごとのカスタマイズ同期"; + readonly ko: "파일별 저장 사용자 설정 동기화"; + readonly ru: "Синхронизация настроек для каждого файла"; + readonly zh: "按文件保存的自定义同步"; + }; + readonly Perform: { + readonly def: "Perform"; + readonly es: "Ejecutar"; + readonly ja: "実行"; + readonly ko: "실행"; + readonly ru: "Выполнить"; + readonly zh: "执行"; + readonly "zh-tw": "執行"; + }; + readonly "Perform cleanup": { + readonly def: "Perform cleanup"; + readonly es: "Ejecutar limpieza"; + readonly ja: "クリーンアップを実行"; + readonly ko: "정리 실행"; + readonly ru: "Выполнить очистку"; + readonly zh: "执行清理"; + readonly "zh-tw": "執行清理"; + }; + readonly "Perform Garbage Collection": { + readonly def: "Perform Garbage Collection"; + readonly es: "Ejecutar recolección de basura"; + readonly ja: "ガーベジコレクションを実行"; + readonly ko: "가비지 컬렉션 실행"; + readonly ru: "Выполнить сборку мусора"; + readonly zh: "执行垃圾回收"; + readonly "zh-tw": "執行垃圾回收"; + }; + readonly "Perform Garbage Collection to remove unused chunks and reduce database size.": { + readonly def: "Perform Garbage Collection to remove unused chunks and reduce database size."; + readonly es: "Ejecuta la recolección de basura para eliminar chunks no usados y reducir el tamaño de la base de datos."; + readonly ja: "未使用のチャンクを削除し、データベースサイズを削減するためにガーベジコレクションを実行します。"; + readonly ko: "사용하지 않는 청크를 제거하고 데이터베이스 크기를 줄이기 위해 가비지 컬렉션을 실행합니다."; + readonly ru: "Выполняет сборку мусора, чтобы удалить неиспользуемые чанки и уменьшить размер базы данных."; + readonly zh: "执行垃圾回收以清理未使用的 chunks 并减小数据库体积。"; + readonly "zh-tw": "執行垃圾回收以移除未使用的 chunks 並減少資料庫大小。"; + }; + readonly "Periodic Sync interval": { + readonly def: "Periodic Sync interval"; + readonly es: "Intervalo de sincronización periódica"; + readonly fr: "Intervalle de synchronisation périodique"; + readonly he: "מרווח סנכרון תקופתי"; + readonly ja: "定時同期の感覚"; + readonly ko: "주기적 동기화 간격"; + readonly ru: "Интервал периодической синхронизации"; + readonly zh: "定期同步间隔"; + }; + readonly "Pick a file to resolve conflict": { + readonly def: "Pick a file to resolve conflict"; + readonly es: "Elegir un archivo para resolver el conflicto"; + readonly ja: "競合を解決するファイルを選択"; + readonly ko: "충돌을 해결할 파일 선택"; + readonly ru: "Выбрать файл для разрешения конфликта"; + readonly zh: "选择要解决冲突的文件"; + readonly "zh-tw": "選擇要解決衝突的檔案"; + }; + readonly "Pick a file to show history": { + readonly def: "Pick a file to show history"; + readonly "zh-tw": "選擇要顯示歷程的檔案"; + }; + readonly "Please disable 'Read chunks online' in settings to use Garbage Collection.": { + readonly def: "Please disable 'Read chunks online' in settings to use Garbage Collection."; + readonly ja: "Garbage Collection を使うには、設定で「Read chunks online」を無効にしてください。"; + readonly ko: "Garbage Collection을 사용하려면 설정에서 \"Read chunks online\"을 비활성화해 주세요."; + readonly ru: "Чтобы использовать Garbage Collection, отключите в настройках «Read chunks online»."; + readonly zh: "要使用垃圾回收,请在设置中禁用“Read chunks online”。"; + readonly "zh-tw": "若要使用垃圾回收,請在設定中停用「Read chunks online」。"; + }; + readonly "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": { + readonly def: "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection."; + readonly ja: "Garbage Collection を使うには、設定で「Compute revisions for chunks」を有効にしてください。"; + readonly ko: "Garbage Collection을 사용하려면 설정에서 \"Compute revisions for chunks\"를 활성화해 주세요."; + readonly ru: "Чтобы использовать Garbage Collection, включите в настройках «Compute revisions for chunks»."; + readonly zh: "要使用垃圾回收,请在设置中启用“Compute revisions for chunks”。"; + readonly "zh-tw": "若要使用垃圾回收,請在設定中啟用「Compute revisions for chunks」。"; + }; + readonly "Please select 'Cancel' explicitly to cancel this operation.": { + readonly def: "Please select 'Cancel' explicitly to cancel this operation."; + readonly ja: "この操作を中止するには、明示的に「キャンセル」を選択してください。"; + readonly ko: "이 작업을 취소하려면 반드시 \"취소\"를 명시적으로 선택해 주세요."; + readonly ru: "Чтобы отменить эту операцию, явно выберите «Отмена»."; + readonly zh: "如需取消此操作,请明确选择“取消”。"; + readonly "zh-tw": "若要取消此操作,請明確選擇「取消」。"; + }; + readonly "Please select a method to import the settings from another device.": { + readonly def: "Please select a method to import the settings from another device."; + readonly es: "Seleccione un método para importar la configuración desde otro dispositivo。"; + readonly ja: "別の端末から設定を取り込む方法を選択してください。"; + readonly ko: "다른 장치에서 설정을 가져올 방법을 선택해 주세요。"; + readonly ru: "Выберите способ импорта настроек с другого устройства。"; + readonly zh: "请选择一种从其他设备导入设置的方法。"; + readonly "zh-tw": "請選擇一種從其他裝置匯入設定的方法。"; + }; + readonly "Please select an option to proceed": { + readonly def: "Please select an option to proceed"; + readonly es: "Seleccione una opción para continuar"; + readonly ja: "続行するには項目を選択してください"; + readonly ko: "계속하려면 항목을 선택해 주세요"; + readonly ru: "Чтобы продолжить, выберите вариант"; + readonly zh: "请选择一个选项以继续"; + readonly "zh-tw": "請選擇一個選項以繼續"; + }; + readonly "Please select the type of server to which you are connecting.": { + readonly def: "Please select the type of server to which you are connecting."; + readonly es: "Seleccione el tipo de servidor al que se está conectando。"; + readonly ja: "接続するサーバーの種類を選択してください。"; + readonly ko: "연결할 서버 유형을 선택해 주세요。"; + readonly ru: "Выберите тип сервера, к которому вы подключаетесь。"; + readonly zh: "请选择你要连接的服务器类型。"; + readonly "zh-tw": "請選擇你要連線的伺服器類型。"; + }; + readonly "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": { + readonly def: "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature."; + readonly es: "Define un nombre para identificar este dispositivo. Debe ser único entre tus dispositivos. Mientras no esté configurado, no podremos habilitar esta función."; + readonly ja: "このデバイスを識別するためのデバイス名を設定してください。この名前は各デバイスで一意である必要があります。設定されるまで、この機能は有効にできません。"; + readonly ko: "이 장치를 식별할 장치 이름을 설정해 주세요. 이 이름은 장치 간에 고유해야 합니다. 설정되기 전까지는 이 기능을 활성화할 수 없습니다."; + readonly ru: "Укажите имя устройства для идентификации этого устройства. Имя должно быть уникальным среди ваших устройств. Пока оно не задано, мы не можем включить эту функцию."; + readonly zh: "请设置设备名称以标识此设备。该名称在你的所有设备之间应保持唯一;未配置前无法启用此功能。"; + }; + readonly "Please set this device name": { + readonly def: "Please set this device name"; + readonly es: "Define el nombre de este dispositivo"; + readonly ja: "このデバイス名を設定してください"; + readonly ko: "이 장치 이름을 설정해 주세요"; + readonly ru: "Укажите имя этого устройства"; + readonly zh: "请设置此设备名称"; + readonly "zh-tw": "請設定此裝置名稱"; + }; + readonly "Plug-in version": { + readonly def: "Plug-in version"; + readonly ja: "プラグインバージョン"; + readonly ko: "플러그인 버전"; + readonly ru: "Версия плагина"; + readonly zh: "插件版本"; + readonly "zh-tw": "外掛版本"; + }; + readonly "Prepare the 'report' to create an issue": { + readonly def: "Prepare the 'report' to create an issue"; + readonly fr: "Préparer le « rapport » pour créer un ticket"; + readonly he: "הכן 'דו\"ח' ליצירת Issue"; + readonly ja: "Issue 作成用の「レポート」を準備"; + readonly ko: "이슈 생성을 위한 '보고서' 준비"; + readonly ru: "Подготовить «отчёт» для создания Issue"; + readonly zh: "准备 '报告' 以创建问题单"; + readonly "zh-tw": "準備建立 Issue 用的「報告」"; + }; + readonly Presets: { + readonly def: "Presets"; + readonly es: "Preconfiguraciones"; + readonly fr: "Préréglages"; + readonly he: "קביעות מראש"; + readonly ja: "プリセット"; + readonly ko: "프리셋"; + readonly ru: "Пресеты"; + readonly zh: "预设"; + }; + readonly "Proceed Garbage Collection": { + readonly def: "Proceed Garbage Collection"; + readonly ja: "Garbage Collection を続行"; + readonly ko: "Garbage Collection 계속"; + readonly ru: "Продолжить Garbage Collection"; + readonly zh: "继续执行垃圾回收"; + readonly "zh-tw": "繼續執行垃圾回收"; + }; + readonly "Proceed with Setup URI": { + readonly def: "Proceed with Setup URI"; + readonly es: "Continuar con el URI de configuración"; + readonly ja: "Setup URI で続行"; + readonly ko: "설정 URI로 계속"; + readonly ru: "Продолжить с Setup URI"; + readonly zh: "继续使用 Setup URI"; + readonly "zh-tw": "繼續使用 Setup URI"; + }; + readonly "Proceeding with Garbage Collection, ignoring missing nodes.": { + readonly def: "Proceeding with Garbage Collection, ignoring missing nodes."; + readonly ja: "不足しているノードを無視して Garbage Collection を続行します。"; + readonly ko: "누락된 노드를 무시하고 Garbage Collection을 계속 진행합니다."; + readonly ru: "Продолжаем Garbage Collection, игнорируя отсутствующие узлы."; + readonly zh: "正在继续执行垃圾回收,并忽略缺失节点。"; + readonly "zh-tw": "正在繼續執行垃圾回收,並忽略缺失節點。"; + }; + readonly "Proceeding with Garbage Collection.": { + readonly def: "Proceeding with Garbage Collection."; + readonly ja: "Garbage Collection を実行します。"; + readonly ko: "Garbage Collection을 진행합니다."; + readonly ru: "Запускаем Garbage Collection."; + readonly zh: "正在执行垃圾回收。"; + readonly "zh-tw": "正在執行垃圾回收。"; + }; + readonly "Process small files in the foreground": { + readonly def: "Process small files in the foreground"; + readonly es: "Procesar archivos pequeños en primer plano"; + readonly fr: "Traiter les petits fichiers au premier plan"; + readonly he: "עבד קבצים קטנים בחזית"; + readonly ja: "小さいファイルを最前面で処理"; + readonly ko: "포그라운드에서 작은 파일 처리"; + readonly ru: "Обрабатывать маленькие файлы в основном потоке"; + readonly zh: "在前台处理小文件"; + }; + readonly Progress: { + readonly def: "Progress"; + readonly ja: "進捗"; + readonly ko: "진행 상태"; + readonly ru: "Прогресс"; + readonly zh: "进度"; + readonly "zh-tw": "進度"; + }; + readonly "Property Encryption": { + readonly def: "Property Encryption"; + readonly fr: "Chiffrement des propriétés"; + readonly he: "הצפנת מאפיינים"; + readonly ru: "Шифрование свойств"; + readonly zh: "属性加密"; + }; + readonly "PureJS fallback (Fast, W/O WebAssembly)": { + readonly def: "PureJS fallback (Fast, W/O WebAssembly)"; + readonly es: "Alternativa PureJS (rápida, sin WebAssembly)"; + readonly ja: "PureJS フォールバック (高速、WebAssembly なし)"; + readonly ko: "PureJS 대체 방식 (빠름, WebAssembly 없음)"; + readonly ru: "Вариант PureJS (быстрый, без WebAssembly)"; + readonly zh: "PureJS 回退(快速,无 WebAssembly)"; + readonly "zh-tw": "PureJS 回退(快速,無 WebAssembly)"; + }; + readonly "Purge all download/upload cache.": { + readonly def: "Purge all download/upload cache."; + readonly es: "Purga toda la caché de descarga y carga."; + readonly ja: "ダウンロード/アップロードキャッシュをすべて削除します。"; + readonly ko: "모든 다운로드/업로드 캐시를 제거합니다."; + readonly ru: "Очистить весь кэш загрузки/выгрузки."; + readonly zh: "清除所有下载/上传缓存。"; + readonly "zh-tw": "清除所有下載/上傳快取。"; + }; + readonly "Purge all journal counter": { + readonly def: "Purge all journal counter"; + readonly es: "Purgar todos los contadores del diario"; + readonly ja: "すべてのジャーナルカウンターを削除"; + readonly ko: "모든 저널 카운터 삭제"; + readonly ru: "Очистить все счётчики журнала"; + readonly zh: "清除所有日志计数器"; + readonly "zh-tw": "清除所有日誌計數器"; + }; + readonly "Rebuild local and remote database with local files.": { + readonly def: "Rebuild local and remote database with local files."; + readonly es: "Reconstruye la base de datos local y remota usando los archivos locales."; + readonly ja: "ローカルファイルを使ってローカルとリモートのデータベースを再構築します。"; + readonly ko: "로컬 파일로 로컬 및 원격 데이터베이스를 다시 구축합니다."; + readonly ru: "Перестроить локальную и удалённую базы данных на основе локальных файлов."; + readonly zh: "使用本地文件重建本地和远端数据库。"; + readonly "zh-tw": "以本機檔案重建本機與遠端資料庫。"; + }; + readonly "Rebuilding Operations (Remote Only)": { + readonly def: "Rebuilding Operations (Remote Only)"; + readonly es: "Operaciones de reconstrucción (solo remoto)"; + readonly ja: "再構築操作 (リモートのみ)"; + readonly ko: "재구축 작업 (원격 전용)"; + readonly ru: "Операции перестроения (только удалённое хранилище)"; + readonly zh: "重建操作(仅远端)"; + readonly "zh-tw": "重建作業(僅遠端)"; + }; + readonly "Recovery and Repair": { + readonly def: "Recovery and Repair"; + readonly "zh-tw": "修復與修補"; + }; + readonly "Recreate all": { + readonly def: "Recreate all"; + readonly es: "Recrear todo"; + readonly ja: "すべて再作成"; + readonly ko: "모두 다시 생성"; + readonly ru: "Пересоздать всё"; + readonly zh: "全部重建"; + readonly "zh-tw": "全部重建"; + }; + readonly "Recreate missing chunks for all files": { + readonly def: "Recreate missing chunks for all files"; + readonly es: "Recrear fragmentos faltantes para todos los archivos"; + readonly ja: "すべてのファイルの不足チャンクを再作成"; + readonly ko: "모든 파일의 누락된 청크 다시 생성"; + readonly ru: "Пересоздать отсутствующие чанки для всех файлов"; + readonly zh: "为所有文件重建缺失的 chunks"; + readonly "zh-tw": "為所有檔案重建遺失的 chunks"; + }; + readonly "RedFlag.Fetch.Method.Desc": { + readonly def: "How do you want to fetch?\n- Create a local database once before fetching.\n **Low Traffic**, **High CPU**, **Low Risk**\n Recommended if ...\n - Files possibly inconsistent\n - Files were not so much\n- Create local file chunks before fetching.\n **Low Traffic**, **Moderate CPU**, **Low to Moderate Risk**\n Recommended if ...\n - Files probably consistent\n - You have a lot of files.\n- Fetch everything from the remote.\n **High Traffic**, **Low CPU**, **Low to Moderate Risk**\n\n>[!INFO]- Details\n> ## Create a local database once before fetching.\n> **Low Traffic**, **High CPU**, **Low Risk**\n> This option first creates a local database using existing local files before fetching data from the remote source.\n> If matching files exist both locally and remotely, only the differences between them will be transferred.\n> However, files present in both locations will initially be handled as conflicted files. They will be resolved automatically if they are not actually conflicted, but this process may take time.\n> This is generally the safest method, minimizing data loss risk.\n> ## Create local file chunks before fetching.\n> **Low Traffic**, **Moderate CPU**, **Low to Moderate Risk** (depending operation)\n> This option first creates chunks from local files for the database, then fetches data. Consequently, only chunks missing locally are transferred. However, all metadata is taken from the remote source.\n> Local files are then compared against this metadata at launch. The content considered newer will overwrite the older one (by modified time). This outcome is then synchronised back to the remote database.\n> This is generally safe if local files are genuinely the latest timestamp. However, it can cause problems if a file has a newer timestamp but older content (like the initial `welcome.md`).\n> This uses less CPU and faster than \"Create a local database once before fetching\", but it may lead to data loss if not used carefully.\n> ## Fetch everything from the remote.\n> **High Traffic**, **Low CPU**, **Low to Moderate Risk** (depending operation)\n> All things will be fetched from the remote.\n> Similar to the Create local file chunks before fetching, but all chunks are fetched from the remote source.\n> This is the most traditional way to fetch, typically consuming the most network traffic and time. It also carries a similar risk of overwriting remote files to the 'Create local file chunks before fetching' option.\n> However, it is often considered the most stable method because it is the longest-established and most straightforward approach."; + readonly fr: "Comment voulez-vous récupérer ?\n- Créer une base locale avant de récupérer.\n **Trafic faible**, **CPU élevé**, **Risque faible**\n Recommandé si ...\n - Fichiers possiblement incohérents\n - Fichiers peu nombreux\n- Créer des fragments de fichiers locaux avant de récupérer.\n **Trafic faible**, **CPU modéré**, **Risque faible à modéré**\n Recommandé si ...\n - Fichiers probablement cohérents\n - Vous avez beaucoup de fichiers.\n- Tout récupérer depuis le distant.\n **Trafic élevé**, **CPU faible**, **Risque faible à modéré**\n\n>[!INFO]- Détails\n> ## Créer une base locale avant de récupérer.\n> **Trafic faible**, **CPU élevé**, **Risque faible**\n> Cette option crée d'abord une base locale à partir des fichiers locaux existants avant de récupérer les données depuis la source distante.\n> Si des fichiers correspondants existent à la fois localement et à distance, seules les différences entre eux seront transférées.\n> Toutefois, les fichiers présents aux deux emplacements seront initialement traités comme en conflit. Ils seront résolus automatiquement s'ils ne le sont pas réellement, mais ce processus peut prendre du temps.\n> C'est généralement la méthode la plus sûre, minimisant le risque de perte de données.\n> ## Créer des fragments de fichiers locaux avant de récupérer.\n> **Trafic faible**, **CPU modéré**, **Risque faible à modéré** (selon l'opération)\n> Cette option crée d'abord des fragments à partir des fichiers locaux pour la base, puis récupère les données. Par conséquent, seuls les fragments manquants localement sont transférés. Cependant, toutes les métadonnées sont prises de la source distante.\n> Les fichiers locaux sont ensuite comparés à ces métadonnées au lancement. Le contenu considéré comme plus récent écrasera le plus ancien (selon la date de modification). Le résultat est ensuite synchronisé vers la base distante.\n> C'est généralement sûr si les fichiers locaux ont bien l'horodatage le plus récent. Cela peut toutefois poser problème si un fichier a un horodatage plus récent mais un contenu plus ancien (comme le `welcome.md` initial).\n> Cette méthode utilise moins de CPU et est plus rapide que « Créer une base locale avant de récupérer », mais peut entraîner une perte de données si elle n'est pas utilisée avec précaution.\n> ## Tout récupérer depuis le distant.\n> **Trafic élevé**, **CPU faible**, **Risque faible à modéré** (selon l'opération)\n> Tout sera récupéré depuis le distant.\n> Similaire à Créer des fragments de fichiers locaux avant de récupérer, mais tous les fragments sont récupérés depuis la source distante.\n> C'est la façon la plus traditionnelle de récupérer, consommant généralement le plus de trafic réseau et de temps. Elle comporte également un risque similaire d'écraser les fichiers distants à l'option « Créer des fragments de fichiers locaux avant de récupérer ».\n> Elle est toutefois souvent considérée comme la méthode la plus stable car c'est la plus ancienne et la plus directe."; + readonly he: "כיצד ברצונך למשוך?\n- %{RedFlag.Fetch.Method.FetchSafer}.\n **תעבורה נמוכה**, **מעבד גבוה**, **סיכון נמוך**\n מומלץ אם...\n - קבצים עשויים להיות לא עקביים\n - אין הרבה קבצים\n- %{RedFlag.Fetch.Method.FetchSmoother}.\n **תעבורה נמוכה**, **מעבד בינוני**, **סיכון נמוך עד בינוני**\n מומלץ אם...\n - הקבצים ככל הנראה עקביים\n - יש לך הרבה קבצים.\n- %{RedFlag.Fetch.Method.FetchTraditional}.\n **תעבורה גבוהה**, **מעבד נמוך**, **סיכון נמוך עד בינוני**\n\n>[!INFO]- פרטים\n> ## %{RedFlag.Fetch.Method.FetchSafer}.\n> **תעבורה נמוכה**, **מעבד גבוה**, **סיכון נמוך**\n> אפשרות זו יוצרת תחילה מסד נתונים מקומי תוך שימוש בקבצים מקומיים קיימים לפני משיכת נתונים מהמקור המרוחד.\n> אם קיימים קבצים תואמים גם מקומית וגם מרחוק, רק ההפרשים ביניהם יועברו.\n> עם זאת, קבצים הקיימים בשני המקומות יטופלו תחילה כקבצים מתנגשים. הם ייפתרו אוטומטית אם לא מתנגשים בפועל, אך תהליך זה עשוי לקחת זמן.\n> זוהי בדרך כלל השיטה הבטוחה ביותר, ממזערת סיכון לאובדן נתונים.\n> ## %{RedFlag.Fetch.Method.FetchSmoother}.\n> **תעבורה נמוכה**, **מעבד בינוני**, **סיכון נמוך עד בינוני** (תלוי בפעולה)\n> אפשרות זו יוצרת תחילה נתחים מקבצים מקומיים למסד הנתונים, ואז מושכת נתונים. כתוצאה מכך, רק נתחים חסרים מקומית מועברים. עם זאת, כל המטה-נתונים נלקחים מהמקור המרוחד.\n> קבצים מקומיים נבדקים לאחר מכן מול מטה-נתונים אלה בעת ההפעלה. התוכן שנחשב חדש יותר ידרוס את הישן יותר (לפי זמן שינוי).\n> בדרך כלל בטוח אם הקבצים המקומיים הם אכן חדשים ביותר. עם זאת, עלול לגרום לבעיות אם לקובץ יש חותמת זמן חדשה יותר אך תוכן ישן יותר (כמו `welcome.md` ראשוני).\n> שיטה זו משתמשת בפחות מעבד ומהירה יותר מ-\"%{RedFlag.Fetch.Method.FetchSafer}\", אך עלולה להוביל לאובדן נתונים אם לא משתמשים בה בזהירות.\n> ## %{RedFlag.Fetch.Method.FetchTraditional}.\n> **תעבורה גבוהה**, **מעבד נמוך**, **סיכון נמוך עד בינוני** (תלוי בפעולה)\n> הכל יימשך מהשרת המרוחד.\n> דומה ל-%{RedFlag.Fetch.Method.FetchSmoother}, אך כל הנתחים נמשכים מהמקור המרוחד.\n> זוהי הדרך המסורתית ביותר למשיכה, צורכת בדרך כלל את רוב תעבורת הרשת והזמן.\n> עם זאת, היא נחשבת לעתים קרובות לשיטה היציבה ביותר מכיוון שהיא הוותיקה והישירה ביותר."; + readonly ja: "どのようにフェッチしますか?\n- フェッチ前にローカルデータベースを作成\n **低トラフィック**, **高CPU負荷**, **低リスク**\n 推奨条件...\n - ファイルの整合性に不安がある\n - ファイル数がそれほど多くない\n- フェッチ前にローカルファイルチャンクを作成\n **低トラフィック**, **中程CPU負荷**, **低~中リスク**\n 推奨条件...\n - ファイルがおそらく整合している\n - ファイル数が多い\n- リモートからすべてをフェッチ\n **高トラフィック**, **低CPU負荷**, **低~中リスク**\n\n>[!INFO]- 詳細\n> ## フェッチ前にローカルデータベースを作成\n> **低トラフィック**, **高CPU負荷**, **低リスク**\n> このオプションは、リモートからデータをフェッチする前に、既存のローカルファイルを使用してローカルデータベースを作成します。\n> ローカルとリモートの両方に一致するファイルがある場合、差分のみが転送されます。\n> ただし、両方の場所に存在するファイルは最初は競合ファイルとして処理されます。実際に競合していなければ自動的に解決されますが、この処理には時間がかかる場合があります。\n> これは一般的に最も安全な方法で、データ損失のリスクを最小限に抑えます。\n> ## フェッチ前にローカルファイルチャンクを作成\n> **低トラフィック**, **中程CPU負荷**, **低~中リスク**(操作による)\n> このオプションは、最初にローカルファイルからデータベース用のチャンクを作成し、その後データをフェッチします。そのため、ローカルにないチャンクのみが転送されます。ただし、すべてのメタデータはリモートから取得されます。\n> ローカルファイルは起動時にこのメタデータと比較されます。新しいと判断されたコンテンツ(更新日時による)が古いものを上書きします。この結果はリモートデータベースに同期されます。\n> ローカルファイルが本当に最新のタイムスタンプであれば一般的に安全です。ただし、ファイルのタイムスタンプが新しくてもコンテンツが古い場合(初期の`welcome.md`など)は問題が発生する可能性があります。\n> これは\"フェッチ前にローカルデータベースを作成\"よりCPU使用量が少なく高速ですが、注意しないとデータ損失につながる可能性があります。\n> ## リモートからすべてをフェッチ\n> **高トラフィック**, **低CPU負荷**, **低~中リスク**(操作による)\n> すべてのデータがリモートからフェッチされます。\n> フェッチ前にローカルファイルチャンクを作成と似ていますが、すべてのチャンクがリモートからフェッチされます。\n> これは最も従来のフェッチ方法で、通常最もネットワークトラフィックと時間を消費します。'フェッチ前にローカルファイルチャンクを作成'オプションと同様のリモートファイル上書きのリスクがあります。\n> ただし、最も歴史があり簡単なアプローチであるため、最も安定した方法と見なされることが多いです。"; + readonly ko: "어떻게 가져오시겠습니까?\n- 가져오기 전에 로컬 데이터베이스를 한 번 생성. (권장)\n **낮은 트래픽**, **높은 CPU**, **낮은 위험**\n- 가져오기 전에 로컬 파일 청크 생성.\n **낮은 트래픽**, **보통 CPU**, **낮음에서 보통 위험**\n- 원격에서 모든 것 가져오기.\n **높은 트래픽**, **낮은 CPU**, **낮음에서 보통 위험**\n\n>[!INFO]- 세부 사항\n> ## 가져오기 전에 로컬 데이터베이스를 한 번 생성. (권장)\n> **낮은 트래픽**, **높은 CPU**, **낮은 위험**\n> 이 옵션은 원격 소스에서 데이터를 가져오기 전에 기존 로컬 파일을 사용하여 로컬 데이터베이스를 먼저 생성합니다.\n> 로컬과 원격 모두에 일치하는 파일이 있으면 둘 사이의 차이점만 전송됩니다.\n> 하지만 두 위치 모두에 있는 파일은 초기에 충돌 파일로 처리됩니다. 실제로 충돌하지 않는다면 자동으로 해결되지만 이 과정은 시간이 걸릴 수 있습니다.\n> 이는 일반적으로 가장 안전한 방법으로 데이터 손실 위험을 최소화합니다.\n> ## 가져오기 전에 로컬 파일 청크 생성.\n> **낮은 트래픽**, **보통 CPU**, **낮음에서 보통 위험** (작업에 따라)\n> 이 옵션은 먼저 로컬 파일에서 데이터베이스용 청크를 생성한 다음 데이터를 가져옵니다. 따라서 로컬에 없는 청크만 전송됩니다. 하지만 모든 메타데이터는 원격 소스에서 가져옵니다.\n> 그런 다음 로컬 파일이 시작 시 이 메타데이터와 비교됩니다. 더 새로운 것으로 간주되는 콘텐츠가 오래된 것을 덮어씁니다(수정 시간 기준). 이 결과는 원격 데이터베이스에 다시 동기화됩니다.\n> 로컬 파일이 실제로 최신 타임스탬프라면 일반적으로 안전합니다. 하지만 파일이 더 새로운 타임스탬프를 가지고 있지만 더 오래된 콘텐츠를 가지고 있다면(초기 `welcome.md`처럼) 문제가 발생할 수 있습니다.\n> 이는 \"가져오기 전에 로컬 데이터베이스를 한 번 생성\"보다 CPU를 덜 사용하고 더 빠르지만 주의 깊게 사용하지 않으면 데이터 손실로 이어질 수 있습니다.\n> ## 원격에서 모든 것 가져오기.\n> **높은 트래픽**, **낮은 CPU**, **낮음에서 보통 위험** (작업에 따라)\n> 모든 것이 원격에서 가져와집니다.\n> 가져오기 전에 로컬 파일 청크 생성와 유사하지만 모든 청크가 원격 소스에서 가져와집니다.\n> 이는 가장 전통적인 가져오기 방법으로 일반적으로 가장 많은 네트워크 트래픽과 시간을 소모합니다. 또한 '가져오기 전에 로컬 파일 청크 생성' 옵션과 유사하게 원격 파일을 덮어쓸 위험이 있습니다.\n> 하지만 가장 오래되고 가장 직접적인 접근 방식이기 때문에 종종 가장 안정적인 방법으로 간주됩니다."; + readonly ru: "Как вы хотите загрузить?"; + readonly zh: "How do you want to fetch?\n- Create a local database once before fetching.\n **Low Traffic**, **High CPU**, **Low Risk**\n Recommended if ...\n - Files possibly inconsistent\n - Files were not so much\n- Create local file chunks before fetching.\n **Low Traffic**, **Moderate CPU**, **Low to Moderate Risk**\n Recommended if ...\n - Files probably consistent\n - You have a lot of files.\n- Fetch everything from the remote.\n **High Traffic**, **Low CPU**, **Low to Moderate Risk**\n\n>[!INFO]- Details\n> ## Create a local database once before fetching.\n> **Low Traffic**, **High CPU**, **Low Risk**\n> This option first creates a local database using existing local files before fetching data from the remote source.\n> If matching files exist both locally and remotely, only the differences between them will be transferred.\n> However, files present in both locations will initially be handled as conflicted files. They will be resolved automatically if they are not actually conflicted, but this process may take time.\n> This is generally the safest method, minimizing data loss risk.\n> ## Create local file chunks before fetching.\n> **Low Traffic**, **Moderate CPU**, **Low to Moderate Risk** (depending operation)\n> This option first creates chunks from local files for the database, then fetches data. Consequently, only chunks missing locally are transferred. However, all metadata is taken from the remote source.\n> Local files are then compared against this metadata at launch. The content considered newer will overwrite the older one (by modified time). This outcome is then synchronised back to the remote database.\n> This is generally safe if local files are genuinely the latest timestamp. However, it can cause problems if a file has a newer timestamp but older content (like the initial `welcome.md`).\n> This uses less CPU and faster than \"Create a local database once before fetching\", but it may lead to data loss if not used carefully.\n> ## Fetch everything from the remote.\n> **High Traffic**, **Low CPU**, **Low to Moderate Risk** (depending operation)\n> All things will be fetched from the remote.\n> Similar to the Create local file chunks before fetching, but all chunks are fetched from the remote source.\n> This is the most traditional way to fetch, typically consuming the most network traffic and time. It also carries a similar risk of overwriting remote files to the 'Create local file chunks before fetching' option.\n> However, it is often considered the most stable method because it is the longest-established and most straightforward approach."; + }; + readonly "RedFlag.Fetch.Method.FetchSafer": { + readonly def: "Create a local database once before fetching"; + readonly fr: "Créer une base locale avant de récupérer"; + readonly he: "צור מסד נתונים מקומי לפני המשיכה"; + readonly ja: "フェッチ前にローカルデータベースを作成"; + readonly ko: "가져오기 전에 로컬 데이터베이스를 한 번 생성"; + readonly ru: "Создать локальную базу данных перед загрузкой"; + readonly zh: "Create a local database once before fetching"; + }; + readonly "RedFlag.Fetch.Method.FetchSmoother": { + readonly def: "Create local file chunks before fetching"; + readonly fr: "Créer des fragments de fichiers locaux avant de récupérer"; + readonly he: "צור נתחי קבצים מקומיים לפני המשיכה"; + readonly ja: "フェッチ前にローカルファイルチャンクを作成"; + readonly ko: "가져오기 전에 로컬 파일 청크 생성"; + readonly ru: "Создать локальные чанки перед загрузкой"; + readonly zh: "Create local file chunks before fetching"; + }; + readonly "RedFlag.Fetch.Method.FetchTraditional": { + readonly def: "Fetch everything from the remote"; + readonly fr: "Tout récupérer depuis le distant"; + readonly he: "משוך הכל מהשרת המרוחד"; + readonly ja: "リモートからすべてをフェッチ"; + readonly ko: "원격에서 모든 것 가져오기"; + readonly ru: "Загрузить всё с удалённого"; + readonly zh: "Fetch everything from the remote"; + }; + readonly "RedFlag.Fetch.Method.Title": { + readonly def: "How do you want to fetch?"; + readonly fr: "Comment voulez-vous récupérer ?"; + readonly he: "כיצד ברצונך למשוך?"; + readonly ja: "どのようにフェッチしますか?"; + readonly ko: "어떻게 가져오시겠습니까?"; + readonly ru: "Как вы хотите загрузить?"; + readonly zh: "How do you want to fetch?"; + }; + readonly "RedFlag.FetchRemoteConfig.Buttons.Cancel": { + readonly def: "No, use local settings"; + readonly fr: "Non, utiliser les paramètres locaux"; + readonly he: "לא, השתמש בהגדרות המקומיות"; + readonly ja: "いいえ、ローカル設定を使用"; + readonly ru: "Нет, использовать локальные настройки"; + readonly zh: "No, use local settings"; + }; + readonly "RedFlag.FetchRemoteConfig.Buttons.Fetch": { + readonly def: "Yes, fetch and apply remote settings"; + readonly fr: "Oui, récupérer et appliquer les paramètres distants"; + readonly he: "כן, משוך והחל הגדרות מרוחקות"; + readonly ja: "はい、リモート設定を取得して適用"; + readonly ru: "Да, загрузить и применить удалённые настройки"; + readonly zh: "Yes, fetch and apply remote settings"; + }; + readonly "RedFlag.FetchRemoteConfig.Message": { + readonly def: "Do you want to fetch and apply remotely stored preference settings to the device?"; + readonly fr: "Voulez-vous récupérer et appliquer les préférences stockées à distance sur cet appareil ?"; + readonly he: "האם ברצונך למשוך ולהחיל הגדרות שמורות מרחוק על מכשיר זה?"; + readonly ja: "リモートに保存された設定を取得して、このデバイスに適用しますか?"; + readonly ru: "Вы хотите загрузить и применить удалённые настройки?"; + readonly zh: "Do you want to fetch and apply remotely stored preference settings to the device?"; + }; + readonly "RedFlag.FetchRemoteConfig.Title": { + readonly def: "Fetch Remote Configuration"; + readonly fr: "Récupérer la configuration distante"; + readonly he: "משוך תצורה מרוחקת"; + readonly ja: "リモート設定の取得"; + readonly ru: "Загрузить удалённую конфигурацию"; + readonly zh: "Fetch Remote Configuration"; + }; + readonly "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client.": { + readonly def: "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client."; + readonly ja: "最新版以外のすべてのリビジョンを破棄して、使用容量を削減します。実行には、リモートサーバーとローカルクライアントの両方に同程度の空き容量が必要です。"; + readonly ko: "최신 버전이 아닌 모든 리비전을 제거하여 저장 공간을 줄입니다. 이 작업을 수행하려면 원격 서버와 로컬 클라이언트에 동일한 양의 여유 공간이 필요합니다."; + readonly zh: "通过丢弃所有非最新版本来减少存储空间。这需要远程服务器和本地客户端具备相同数量的可用空间。"; + readonly "zh-tw": "透過捨棄所有非最新版本來減少儲存空間占用。執行此操作時,遠端伺服器與本機用戶端都需要具備相同數量的可用空間。"; + }; + readonly "Reducing the frequency with which on-disk changes are reflected into the DB": { + readonly def: "Reducing the frequency with which on-disk changes are reflected into the DB"; + readonly es: "Reducir frecuencia de actualizaciones de disco a BD"; + readonly fr: "Réduire la fréquence à laquelle les modifications sur disque sont reflétées dans la base"; + readonly he: "הפחת את תדירות השתקפות שינויים בדיסק למסד הנתונים"; + readonly ja: "ローカルでの変更がデータベースに反映される頻度を下げる(所定の回数まとめて同期する、逐一反映しない)"; + readonly ko: "디스크 변경 사항이 데이터베이스에 반영되는 빈도를 줄입니다"; + readonly ru: "Уменьшение частоты отражения изменений с диска в БД"; + readonly zh: "降低将磁盘上的更改反映到数据库中的频率"; + }; + readonly Region: { + readonly def: "Region"; + readonly es: "Región"; + readonly fr: "Région"; + readonly he: "אזור"; + readonly ja: "リージョン"; + readonly ko: "지역"; + readonly ru: "Регион"; + readonly zh: "区域"; + }; + readonly Remediation: { + readonly def: "Remediation"; + readonly es: "Remediación"; + readonly ja: "是正"; + readonly ko: "복구 조치"; + readonly ru: "Исправление"; + readonly zh: "修复设置"; + readonly "zh-tw": "修復設定"; + }; + readonly "Remediation Setting Changed": { + readonly def: "Remediation Setting Changed"; + readonly es: "La configuración de remediación cambió"; + readonly ja: "是正設定が変更されました"; + readonly ko: "복구 설정이 변경됨"; + readonly ru: "Настройки исправления изменены"; + readonly zh: "修复设置已更改"; + readonly "zh-tw": "修復設定已變更"; + }; + readonly "Remote Database Tweak (In sunset)": { + readonly def: "Remote Database Tweak (In sunset)"; + readonly es: "Ajustes de base de datos remota (en retirada)"; + readonly ja: "リモートデータベースの調整 (廃止予定)"; + readonly ko: "원격 데이터베이스 조정 (폐기 예정)"; + readonly ru: "Настройки удалённой базы данных (устаревает)"; + readonly zh: "远端数据库调优(逐步淘汰)"; + readonly "zh-tw": "遠端資料庫調校(即將淘汰)"; + }; + readonly "Remote Databases": { + readonly def: "Remote Databases"; + readonly es: "Bases de datos remotas"; + readonly ja: "リモートデータベース"; + readonly ko: "원격 데이터베이스"; + readonly ru: "Удалённые базы данных"; + readonly zh: "远端数据库"; + readonly "zh-tw": "遠端資料庫"; + }; + readonly "Remote name": { + readonly def: "Remote name"; + readonly es: "Nombre del remoto"; + readonly ja: "リモート名"; + readonly ko: "원격 이름"; + readonly ru: "Имя удалённого хранилища"; + readonly zh: "远端名称"; + readonly "zh-tw": "遠端名稱"; + }; + readonly "Remote server type": { + readonly def: "Remote server type"; + readonly es: "Tipo de servidor remoto"; + readonly fr: "Type de serveur distant"; + readonly he: "סוג שרת מרוחד"; + readonly ja: "リモートの種別"; + readonly ko: "원격 서버 유형"; + readonly ru: "Тип удалённого сервера"; + readonly zh: "远程服务器类型"; + }; + readonly "Remote Type": { + readonly def: "Remote Type"; + readonly es: "Tipo de remoto"; + readonly fr: "Type de distant"; + readonly he: "סוג מרוחד"; + readonly ja: "同期方式"; + readonly ko: "원격 유형"; + readonly ru: "Удалённый тип"; + readonly zh: "远程类型"; + }; + readonly Rename: { + readonly def: "Rename"; + readonly es: "Renombrar"; + readonly ja: "名前を変更"; + readonly ko: "이름 바꾸기"; + readonly ru: "Переименовать"; + readonly zh: "重命名"; + readonly "zh-tw": "重新命名"; + }; + readonly "Replicator.Dialogue.Locked.Action.Dismiss": { + readonly def: "Cancel for reconfirmation"; + readonly fr: "Annuler pour reconfirmer"; + readonly he: "ביטול לאישור מחדש"; + readonly ja: "再確認のためキャンセル"; + readonly ko: "재확인을 위해 취소"; + readonly ru: "Отмена для подтверждения"; + readonly zh: "Cancel for reconfirmation"; + }; + readonly "Replicator.Dialogue.Locked.Action.Fetch": { + readonly def: "Reset Synchronisation on This Device"; + readonly fr: "Réinitialiser la synchronisation sur cet appareil"; + readonly he: "אפס סנכרון במכשיר זה"; + readonly ja: "このデバイスの同期をリセット"; + readonly ko: "원격 데이터베이스에서 모든 것을 다시 가져오기"; + readonly ru: "Сбросить синхронизацию на этом устройстве"; + readonly zh: "Reset Synchronisation on This Device"; + }; + readonly "Replicator.Dialogue.Locked.Action.Unlock": { + readonly def: "Unlock the remote database"; + readonly fr: "Déverrouiller la base distante"; + readonly he: "בטל נעילת מסד הנתונים המרוחד"; + readonly ja: "リモートデータベースのロックを解除"; + readonly ko: "원격 데이터베이스 잠금 해제"; + readonly ru: "Разблокировать удалённую базу данных"; + readonly zh: "Unlock the remote database"; + }; + readonly "Replicator.Dialogue.Locked.Message": { + readonly def: "Remote database is locked. This is due to a rebuild on one of the terminals.\nThe device is therefore asked to withhold the connection to avoid database corruption.\n\nThere are three options that we can do:\n\n- Reset Synchronisation on This Device\n The most preferred and reliable way. This will dispose the local database once, and reset all synchronisation information from the remote database again, In most case, we can perform this safely. However, it takes some time and should be done in stable network.\n- Unlock the remote database\n This method can only be used if we are already reliably synchronised by other replication methods. This does not simply mean that we have the same files. If you are not sure, you should avoid it.\n- Cancel for reconfirmation\n This will cancel the operation. And we will asked again on next request.\n"; + readonly fr: "La base distante est verrouillée. Ceci est dû à une reconstruction sur l'un des terminaux.\nL'appareil est donc prié de suspendre la connexion pour éviter la corruption de la base.\n\nTrois options sont possibles :\n\n- Réinitialiser la synchronisation sur cet appareil\n La méthode la plus recommandée et fiable. Elle supprime la base locale puis réinitialise toutes les informations de synchronisation depuis la base distante. Dans la plupart des cas, c'est sûr. Cela prend cependant du temps et devrait se faire sur un réseau stable.\n- Déverrouiller la base distante\n Cette méthode ne peut être utilisée que si nous sommes déjà synchronisés de manière fiable par d'autres méthodes de réplication. Cela ne signifie pas simplement que nous avons les mêmes fichiers. Dans le doute, évitez.\n- Annuler pour reconfirmer\n Ceci annule l'opération. Vous serez à nouveau interrogé à la prochaine requête.\n"; + readonly he: "מסד הנתונים המרוחד נעול. הסיבה היא בנייה מחדש באחד הטרמינלים.\nלכן המכשיר מתבקש להמנע מחיבור כדי למנוע פגיעה במסד הנתונים.\n\nקיימות שלוש אפשרויות:\n\n- %{Replicator.Dialogue.Locked.Action.Fetch}\n הדרך המועדפת והאמינה ביותר. פעולה זו תמחק את מסד הנתונים המקומי פעם,\n ותאפס את כל מידע הסנכרון ממסד הנתונים המרוחד מחדש. ברוב המקרים ניתן\n לעשות זאת בבטחה. עם זאת, דורשת זמן ויש לבצע ברשת יציבה.\n- %{Replicator.Dialogue.Locked.Action.Unlock}\n ניתן להשתמש בשיטה זו רק אם כבר מסונכרנים באופן אמין בשיטות שכפול\n אחרות. פשוט לא מספיק שיש אותם קבצים. אם אינך בטוח, הימנע מכך.\n- %{Replicator.Dialogue.Locked.Action.Dismiss}\n פעולה זו תבטל את הפעולה. תתבקש שוב בבקשה הבאה.\n"; + readonly ja: "リモートデータベースがロックされています。これはいずれかの端末での再構築が原因です。\nデータベースの破損を避けるため、このデバイスは接続を保留するよう求められています。\n\n3つのオプションがあります:\n\n- このデバイスの同期をリセット\n 最も推奨される信頼性の高い方法です。ローカルデータベースを一度破棄し、リモートデータベースからすべての同期情報を再取得します。ほとんどの場合、これは安全に実行できます。ただし、時間がかかり、安定したネットワークで実行する必要があります。\n- リモートデータベースのロックを解除\n この方法は、他のレプリケーション(複製)方法ですでに確実に同期されている場合のみ使用できます。単に同じファイルがあるという意味ではありません。確信がない場合は避けてください。\n- 再確認のためキャンセル\n 操作をキャンセルします。次回のリクエスト時に再度確認されます。\n"; + readonly ko: "원격 데이터베이스가 잠겨 있습니다. 이는 일부 터미널에서 데이터베이스를 재구축했기 때문입니다.\n따라서 현재 기기는 데이터베이스 손상을 방지하기 위해 연결을 일시적으로 보류해야 합니다.\n\n선택할 수 있는 세 가지 방법이 있습니다:\n\n- 원격 데이터베이스에서 모든 것을 다시 가져오기\n 가장 권장되고 신뢰할 수 있는 방법입니다. 로컬 데이터베이스를 초기화한 뒤, 원격 데이터베이스의 전체 데이터를 다시 가져옵니다. 대부분의 경우 안전하게 수행할 수 있으나, 시간이 다소 걸리며 안정적인 네트워크 환경에서 진행해야 합니다.\n- 원격 데이터베이스 잠금 해제\n 이 방법은 다른 동기화 방식으로 이미 완전하고 안정적으로 동기화된 경우에만 사용할 수 있습니다. 단순히 파일이 같다는 의미가 아니므로, 확신이 없다면 사용을 피하는 것이 좋습니다.\n- 재확인을 위해 취소\n 이번 작업을 취소하고, 다음 요청 시 다시 안내받습니다.\n"; + readonly ru: "Удалённая база данных заблокирована. Это связано с перестроением на одном из устройств."; + readonly zh: "Remote database is locked. This is due to a rebuild on one of the terminals.\nThe device is therefore asked to withhold the connection to avoid database corruption.\n\nThere are three options that we can do:\n\n- Reset Synchronisation on This Device\n The most preferred and reliable way. This will dispose the local database once, and fetch all from the remote database again, In most case, we can perform this safely. However, it takes some time and should be done in stable network.\n- Unlock the remote database\n This method can only be used if we are already reliably synchronised by other replication methods. This does not simply mean that we have the same files. If you are not sure, you should avoid it.\n- Cancel for reconfirmation\n This will cancel the operation. And we will asked again on next request.\n"; + }; + readonly "Replicator.Dialogue.Locked.Message.Fetch": { + readonly def: "Fetch all has been scheduled. Plug-in will be restarted to perform it."; + readonly fr: "Tout récupérer a été planifié. Le plug-in sera redémarré pour l'exécuter."; + readonly he: "משיכה מלאה תוזמנה. הפלאגין יופעל מחדש לביצועה."; + readonly ja: "全フェッチがスケジュールされました。プラグインは実行のために再起動されます。"; + readonly ko: "모든 것 가져오기가 예약되었습니다. 이를 수행하기 위해 플러그인이 재시작됩니다."; + readonly ru: "Загрузка всего запланирована. Плагин будет перезапущен."; + readonly zh: "Fetch all has been scheduled. Plug-in will be restarted to perform it."; + }; + readonly "Replicator.Dialogue.Locked.Message.Unlocked": { + readonly def: "The remote database has been unlocked. Please retry the operation."; + readonly fr: "La base distante a été déverrouillée. Veuillez réessayer l'opération."; + readonly he: "מסד הנתונים המרוחד בוטל נעילתו. אנא נסה שוב את הפעולה."; + readonly ja: "リモートデータベースのロックが解除されました。操作を再試行してください。"; + readonly ko: "원격 데이터베이스 잠금이 해제되었습니다. 작업을 다시 시도해 주세요."; + readonly ru: "Удалённая база данных разблокирована. Повторите операцию."; + readonly zh: "The remote database has been unlocked. Please retry the operation."; + }; + readonly "Replicator.Dialogue.Locked.Title": { + readonly def: "Locked"; + readonly fr: "Verrouillée"; + readonly he: "נעול"; + readonly ja: "ロック中"; + readonly ko: "잠김"; + readonly ru: "Заблокировано"; + readonly zh: "Locked"; + }; + readonly "Replicator.Message.Cleaned": { + readonly def: "Database cleaning up is in process. replication has been cancelled"; + readonly fr: "Nettoyage de la base en cours. La réplication a été annulée"; + readonly he: "ניקוי מסד הנתונים בתהליך. השכפול בוטל"; + readonly ja: "データベースのクリーナップ中です。レプリケーション(複製)はキャンセルされました。"; + readonly ko: "데이터베이스 정리가 진행 중입니다. 복제가 취소되었습니다"; + readonly ru: "Очистка базы данных в процессе. Репликация отменена"; + readonly zh: "Database cleaning up is in process. replication has been cancelled"; + }; + readonly "Replicator.Message.InitialiseFatalError": { + readonly def: "No replicator is available, this is the fatal error."; + readonly fr: "Aucun réplicateur disponible, il s'agit d'une erreur fatale."; + readonly he: "אין רפליקטור זמין, זוהי שגיאה קריטית."; + readonly ja: "レプリケーターが利用できません。これは致命的なエラーです。"; + readonly ko: "사용 가능한 복제기가 없습니다. 치명적인 오류입니다."; + readonly ru: "Репликатор недоступен, это фатальная ошибка."; + readonly zh: "No replicator is available, this is the fatal error."; + }; + readonly "Replicator.Message.Pending": { + readonly def: "Some file events are pending. Replication has been cancelled."; + readonly fr: "Des événements de fichier sont en attente. La réplication a été annulée."; + readonly he: "חלק מאירועי הקבצים ממתינים. השכפול בוטל."; + readonly ja: "ファイルイベントが保留中です。レプリケーション(複製)はキャンセルされました。"; + readonly ko: "일부 파일 이벤트가 대기 중입니다. 복제가 취소되었습니다."; + readonly ru: "Некоторые события файлов ожидают. Репликация отменена."; + readonly zh: "Some file events are pending. Replication has been cancelled."; + }; + readonly "Replicator.Message.SomeModuleFailed": { + readonly def: "Replication has been cancelled by some module failure"; + readonly fr: "La réplication a été annulée suite à l'échec d'un module"; + readonly he: "השכפול בוטל בשל כשל במודול"; + readonly ja: "一部のモジュールの失敗によりレプリケーション(複製)がキャンセルされました。"; + readonly ko: "일부 모듈 실패로 복제가 취소되었습니다"; + readonly ru: "Репликация отменена из-за сбоя модуля"; + readonly zh: "Replication has been cancelled by some module failure"; + }; + readonly "Replicator.Message.VersionUpFlash": { + readonly def: "An update has been detected. Please open the Settings dialogue and check the Change Log. Replication has been cancelled."; + readonly fr: "Une mise à jour a été détectée. Veuillez ouvrir la boîte de dialogue des paramètres et consulter le journal des modifications. La réplication a été annulée."; + readonly he: "זוהה עדכון. אנא פתח את דיאלוג ההגדרות ובדוק את יומן השינויים. השכפול בוטל."; + readonly ja: "更新が検出されました。設定ダイアログを開いて変更ログを確認してください。レプリケーション(複製)はキャンセルされました。"; + readonly ko: "설정을 열고 메시지를 확인해 주세요. 복제가 취소되었습니다."; + readonly ru: "Обновление обнаружено. Откройте настройки и проверьте историю изменений."; + readonly zh: "An update has been detected. Please open the Settings dialogue and check the Change Log. Replication has been cancelled."; + }; + readonly "Requires restart of Obsidian": { + readonly def: "Requires restart of Obsidian"; + readonly es: "Requiere reiniciar Obsidian"; + readonly fr: "Nécessite un redémarrage d'Obsidian"; + readonly he: "דורש הפעלה מחדש של Obsidian"; + readonly ja: "Obsidianの再起動が必要です"; + readonly ko: "Obsidian 재시작 필요"; + readonly ru: "Требуется перезапуск Obsidian"; + readonly zh: "需要重启 Obsidian"; + }; + readonly "Requires restart of Obsidian.": { + readonly def: "Requires restart of Obsidian."; + readonly es: "Requiere reiniciar Obsidian"; + readonly fr: "Nécessite un redémarrage d'Obsidian."; + readonly he: "דורש הפעלה מחדש של Obsidian."; + readonly ja: "Obsidianの再起動が必要です。"; + readonly ko: "Obsidian 재시작이 필요합니다."; + readonly ru: "Требуется перезапуск Obsidian."; + readonly zh: "需要重启 Obsidian "; + }; + readonly "Rerun Onboarding Wizard": { + readonly def: "Rerun Onboarding Wizard"; + readonly fr: "Relancer l'assistant d'intégration"; + readonly he: "הרץ שוב את אשף ההכוונה"; + readonly ja: "オンボーディングウィザードを再実行"; + readonly ko: "온보딩 마법사 다시 실행"; + readonly ru: "Перезапустить мастер настройки"; + readonly zh: "重新运行引导向导"; + readonly "zh-tw": "重新執行導覽精靈"; + }; + readonly "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": { + readonly def: "Rerun the onboarding wizard to set up Self-hosted LiveSync again."; + readonly fr: "Relancer l'assistant d'intégration pour reconfigurer Self-hosted LiveSync."; + readonly he: "הרץ שוב את אשף ההכוונה להגדרת Self-hosted LiveSync מחדש."; + readonly ja: "オンボーディングウィザードを再実行して、Self-hosted LiveSync をもう一度設定します。"; + readonly ko: "온보딩 마법사를 다시 실행하여 Self-hosted LiveSync를 다시 설정합니다."; + readonly ru: "Перезапустить мастер настройки для повторной настройки Self-hosted LiveSync."; + readonly zh: "重新运行引导向导以再次设置 Self-hosted LiveSync。"; + readonly "zh-tw": "重新執行導覽精靈以再次設定 Self-hosted LiveSync。"; + }; + readonly "Rerun Wizard": { + readonly def: "Rerun Wizard"; + readonly fr: "Relancer l'assistant"; + readonly he: "הרץ שוב את האשף"; + readonly ja: "ウィザードを再実行"; + readonly ko: "마법사 다시 실행"; + readonly ru: "Перезапустить мастер"; + readonly zh: "重新运行向导"; + readonly "zh-tw": "重新執行精靈"; + }; + readonly Resend: { + readonly def: "Resend"; + readonly es: "Reenviar"; + readonly ja: "再送信"; + readonly ko: "다시 보내기"; + readonly ru: "Повторно отправить"; + readonly zh: "重新发送"; + readonly "zh-tw": "重新傳送"; + }; + readonly "Resend all chunks to the remote.": { + readonly def: "Resend all chunks to the remote."; + readonly es: "Reenvía todos los chunks al remoto."; + readonly ja: "すべてのチャンクをリモートへ再送信します。"; + readonly ko: "모든 청크를 원격으로 다시 보냅니다."; + readonly ru: "Повторно отправить все чанки в удалённое хранилище."; + readonly zh: "将所有 chunks 重新发送到远端。"; + readonly "zh-tw": "將所有 chunks 重新傳送到遠端。"; + }; + readonly Reset: { + readonly def: "Reset"; + readonly es: "Restablecer"; + readonly ja: "リセット"; + readonly ko: "재설정"; + readonly ru: "Сброс"; + readonly zh: "重置"; + readonly "zh-tw": "重設"; + }; + readonly "Reset all": { + readonly def: "Reset all"; + readonly es: "Restablecer todo"; + readonly ja: "すべてリセット"; + readonly ko: "모두 재설정"; + readonly ru: "Сбросить всё"; + readonly zh: "全部重置"; + readonly "zh-tw": "全部重設"; + }; + readonly "Reset all journal counter": { + readonly def: "Reset all journal counter"; + readonly es: "Restablecer todos los contadores del diario"; + readonly ja: "すべてのジャーナルカウンターをリセット"; + readonly ko: "모든 저널 카운터 재설정"; + readonly ru: "Сбросить все счётчики журнала"; + readonly zh: "重置所有日志计数器"; + readonly "zh-tw": "重設所有日誌計數器"; + }; + readonly "Reset journal received history": { + readonly def: "Reset journal received history"; + readonly es: "Restablecer historial de recepción del diario"; + readonly ja: "ジャーナル受信履歴をリセット"; + readonly ko: "저널 수신 기록 재설정"; + readonly ru: "Сбросить историю полученных записей журнала"; + readonly zh: "重置日志接收历史"; + readonly "zh-tw": "重設日誌接收歷史"; + }; + readonly "Reset journal sent history": { + readonly def: "Reset journal sent history"; + readonly es: "Restablecer historial de envío del diario"; + readonly ja: "ジャーナル送信履歴をリセット"; + readonly ko: "저널 송신 기록 재설정"; + readonly ru: "Сбросить историю отправленных записей журнала"; + readonly zh: "重置日志发送历史"; + readonly "zh-tw": "重設日誌傳送歷史"; + }; + readonly "Reset notification threshold and check the remote database usage": { + readonly def: "Reset notification threshold and check the remote database usage"; + readonly fr: "Réinitialiser le seuil de notification et vérifier l'utilisation de la base distante"; + readonly he: "אפס סף התראה ובדוק שימוש במסד הנתונים המרוחד"; + readonly ja: "通知しきい値をリセットしてリモートデータベース使用量を確認"; + readonly ko: "알림 임계값을 초기화하고 원격 데이터베이스 사용량 확인"; + readonly ru: "Сбросить порог уведомления и проверить использование удалённой базы данных"; + readonly zh: "重置通知阈值并检查远程数据库使用情况"; + readonly "zh-tw": "重設通知閾值並檢查遠端資料庫使用情況"; + }; + readonly "Reset received": { + readonly def: "Reset received"; + readonly es: "Restablecer recepción"; + readonly ja: "受信履歴をリセット"; + readonly ko: "수신 기록 재설정"; + readonly ru: "Сбросить полученные"; + readonly zh: "重置接收记录"; + readonly "zh-tw": "重設接收紀錄"; + }; + readonly "Reset sent history": { + readonly def: "Reset sent history"; + readonly es: "Restablecer historial de envío"; + readonly ja: "送信履歴をリセット"; + readonly ko: "송신 기록 재설정"; + readonly ru: "Сбросить историю отправки"; + readonly zh: "重置发送历史"; + readonly "zh-tw": "重設傳送歷史"; + }; + readonly "Reset Synchronisation information": { + readonly def: "Reset Synchronisation information"; + readonly es: "Restablecer información de sincronización"; + readonly ja: "同期情報をリセット"; + readonly ko: "동기화 정보 재설정"; + readonly ru: "Сбросить информацию о синхронизации"; + readonly zh: "重置同步信息"; + readonly "zh-tw": "重設同步資訊"; + }; + readonly "Reset Synchronisation on This Device": { + readonly def: "Reset Synchronisation on This Device"; + readonly es: "Restablecer sincronización en este dispositivo"; + readonly ja: "このデバイスの同期状態をリセット"; + readonly ko: "이 장치의 동기화 상태 재설정"; + readonly ru: "Сбросить синхронизацию на этом устройстве"; + readonly zh: "重置此设备上的同步"; + readonly "zh-tw": "重設此裝置上的同步"; + }; + readonly "Reset the remote storage size threshold and check the remote storage size again.": { + readonly def: "Reset the remote storage size threshold and check the remote storage size again."; + readonly fr: "Réinitialiser le seuil de taille du stockage distant et vérifier à nouveau la taille du stockage distant."; + readonly he: "אפס את סף גודל האחסון המרוחד ובדוק שוב את גודל האחסון המרוחד."; + readonly ja: "リモートストレージ容量のしきい値をリセットし、リモートストレージ容量を再確認します。"; + readonly ko: "원격 저장소 크기 임계값을 초기화하고 원격 저장소 크기를 다시 확인합니다."; + readonly ru: "Сбросить порог размера удалённого хранилища и проверить размер хранилища снова."; + readonly zh: "重置远程存储大小阈值并再次检查远程存储大小。"; + readonly "zh-tw": "重設遠端儲存空間大小閾值,並再次檢查遠端儲存空間大小。"; + }; + readonly "Resolve All": { + readonly def: "Resolve All"; + readonly es: "Resolver todo"; + readonly ja: "すべて解決"; + readonly ko: "모두 해결"; + readonly ru: "Разрешить всё"; + readonly zh: "全部处理"; + readonly "zh-tw": "全部處理"; + }; + readonly "Resolve all conflicted files": { + readonly def: "Resolve all conflicted files"; + readonly es: "Resolver todos los archivos en conflicto"; + readonly ja: "競合しているすべてのファイルを解決"; + readonly ko: "충돌한 모든 파일 해결"; + readonly ru: "Разрешить все конфликтующие файлы"; + readonly zh: "解决所有冲突文件"; + readonly "zh-tw": "解決所有衝突檔案"; + }; + readonly "Resolve All conflicted files by the newer one": { + readonly def: "Resolve All conflicted files by the newer one"; + readonly es: "Resolver todos los archivos en conflicto con la versión más reciente"; + readonly ja: "競合したすべてのファイルを新しい方で解決"; + readonly ko: "충돌한 모든 파일을 최신 버전으로 해결"; + readonly ru: "Разрешить все конфликтующие файлы в пользу более новой версии"; + readonly zh: "将所有冲突文件解析为较新的版本"; + readonly "zh-tw": "將所有衝突檔案統一為較新的版本"; + }; + readonly "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": { + readonly def: "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one."; + readonly es: "Resuelve todos los archivos en conflicto conservando la versión más reciente. Precaución: esto sobrescribirá la versión anterior y no podrá recuperarse."; + readonly ja: "競合しているすべてのファイルを新しい方の内容で解決します。注意:古い方は上書きされ、復元できません。"; + readonly ko: "충돌한 모든 파일을 더 최신 버전으로 해결합니다. 주의: 이전 버전은 덮어써지며 복원할 수 없습니다."; + readonly ru: "Разрешает все конфликтующие файлы в пользу более новой версии. Внимание: старая версия будет перезаписана и её нельзя будет восстановить."; + readonly zh: "将所有冲突文件统一保留较新的版本。注意:这会覆盖较旧的版本,且被覆盖的内容无法恢复。"; + readonly "zh-tw": "將所有衝突檔案統一保留較新的版本。注意:這會覆寫較舊的版本,且被覆寫的內容無法復原。"; + }; + readonly "Restart Now": { + readonly def: "Restart Now"; + readonly es: "Reiniciar ahora"; + readonly ja: "今すぐ再起動"; + readonly ko: "지금 재시작"; + readonly ru: "Перезапустить сейчас"; + readonly zh: "立即重启"; + readonly "zh-tw": "立即重新啟動"; + }; + readonly "Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?": { + readonly def: "Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?"; + readonly "zh-tw": "強烈建議重新啟動 Obsidian。在重新啟動之前,部分變更可能尚未生效,顯示也可能不一致。你確定要現在重新啟動嗎?"; + }; + readonly "Restore or reconstruct local database from remote.": { + readonly def: "Restore or reconstruct local database from remote."; + readonly es: "Restaura o reconstruye la base de datos local desde el remoto."; + readonly ja: "リモートからローカルデータベースを復元または再構築します。"; + readonly ko: "원격에서 로컬 데이터베이스를 복원하거나 재구축합니다."; + readonly ru: "Восстановить или перестроить локальную базу данных из удалённой."; + readonly zh: "从远端恢复或重建本地数据库。"; + readonly "zh-tw": "從遠端還原或重建本機資料庫。"; + }; + readonly "Run Doctor": { + readonly def: "Run Doctor"; + readonly fr: "Lancer le Docteur"; + readonly he: "הפעל Doctor"; + readonly ja: "診断を実行"; + readonly ko: "진단 실행"; + readonly ru: "Запустить диагностику"; + readonly zh: "立即诊断"; + readonly "zh-tw": "執行診斷"; + }; + readonly "S3/MinIO/R2 Object Storage": { + readonly def: "S3/MinIO/R2 Object Storage"; + readonly es: "Almacenamiento de objetos S3/MinIO/R2"; + readonly ja: "S3/MinIO/R2 オブジェクトストレージ"; + readonly ko: "S3/MinIO/R2 객체 스토리지"; + readonly ru: "Объектное хранилище S3/MinIO/R2"; + readonly zh: "S3/MinIO/R2 对象存储"; + readonly "zh-tw": "S3/MinIO/R2 物件儲存"; + }; + readonly "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": { + readonly def: "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform."; + readonly es: "Guardar configuración en archivo markdown. Se notificarán nuevos ajustes. Puede definir diferentes archivos por plataforma"; + readonly fr: "Enregistrer les paramètres dans un fichier markdown. Vous serez notifié à l'arrivée de nouveaux paramètres. Vous pouvez définir des fichiers différents selon la plateforme."; + readonly he: "שמור הגדרות לקובץ Markdown. תיודע כשהגדרות חדשות יגיעו. ניתן להגדיר קבצים שונים לפי פלטפורמה."; + readonly ja: "Markdownファイルに設定を保存します。新しい設定が到着すると通知されます。プラットフォームごとに異なるファイルを設定できます。"; + readonly ko: "설정을 마크다운 파일에 저장합니다. 새로운 설정이 도착하면 알림을 받게 됩니다. 플랫폼별로 다른 파일을 설정할 수 있습니다."; + readonly ru: "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform."; + readonly zh: "将设置保存到一个 Markdown 文件中。当新设置到达时,您将收到通知。您可以根据平台设置不同的文件 "; + }; + readonly "Saving will be performed forcefully after this number of seconds.": { + readonly def: "Saving will be performed forcefully after this number of seconds."; + readonly es: "Guardado forzado tras esta cantidad de segundos"; + readonly fr: "L'enregistrement sera forcé au bout de ce nombre de secondes."; + readonly he: "השמירה תתבצע בכפייה לאחר מספר שניות זה."; + readonly ja: "この秒数後に強制的に保存されます。"; + readonly ko: "이 시간(초) 후에 강제로 저장이 수행됩니다."; + readonly ru: "Сохранение будет принудительно выполнено после этого количества секунд."; + readonly zh: "在此秒数后将强制执行保存 "; + }; + readonly "Scan a QR Code (Recommended for mobile)": { + readonly def: "Scan a QR Code (Recommended for mobile)"; + readonly es: "Escanear un código QR (recomendado para móviles)"; + readonly ja: "QR コードをスキャンする(モバイル推奨)"; + readonly ko: "QR 코드 스캔(모바일 권장)"; + readonly ru: "Сканировать QR-код (рекомендуется для мобильных устройств)"; + readonly zh: "扫描二维码(移动端推荐)"; + readonly "zh-tw": "掃描 QR Code(行動裝置推薦)"; + }; + readonly "Scan changes on customization sync": { + readonly def: "Scan changes on customization sync"; + readonly es: "Escanear cambios en sincronización de personalización"; + readonly fr: "Analyser les modifications de synchronisation de personnalisation"; + readonly he: "סרוק שינויים בסנכרון התאמה אישית"; + readonly ja: "カスタマイズされた同期時に、変更をスキャンする"; + readonly ko: "사용자 설정 동기화 시 변경 사항 검색"; + readonly ru: "Сканировать изменения при синхронизации настроек"; + readonly zh: "在自定义同步时扫描更改"; + }; + readonly "Scan customization automatically": { + readonly def: "Scan customization automatically"; + readonly es: "Escanear personalización automáticamente"; + readonly fr: "Analyser automatiquement la personnalisation"; + readonly he: "סרוק התאמה אישית אוטומטית"; + readonly ja: "自動的にカスタマイズをスキャン"; + readonly ko: "사용자 설정 자동 검색"; + readonly ru: "Сканировать настройки автоматически"; + readonly zh: "自动扫描自定义设置"; + }; + readonly "Scan customization before replicating.": { + readonly def: "Scan customization before replicating."; + readonly es: "Escanear personalización antes de replicar"; + readonly fr: "Analyser la personnalisation avant de répliquer."; + readonly he: "סרוק התאמה אישית לפני שכפול."; + readonly ja: "レプリケーション(複製)前に、カスタマイズをスキャン"; + readonly ko: "복제하기 전에 사용자 설정을 검색합니다."; + readonly ru: "Сканировать настройки перед репликацией."; + readonly zh: "在复制前扫描自定义设置 "; + }; + readonly "Scan customization every 1 minute.": { + readonly def: "Scan customization every 1 minute."; + readonly es: "Escanear personalización cada 1 minuto"; + readonly fr: "Analyser la personnalisation toutes les 1 minute."; + readonly he: "סרוק התאמה אישית כל דקה."; + readonly ja: "カスタマイズのスキャンを1分ごとに行う"; + readonly ko: "1분마다 사용자 설정을 검색합니다."; + readonly ru: "Сканировать настройки каждую минуту."; + readonly zh: "每1分钟扫描自定义设置 "; + }; + readonly "Scan customization periodically": { + readonly def: "Scan customization periodically"; + readonly es: "Escanear personalización periódicamente"; + readonly fr: "Analyser la personnalisation périodiquement"; + readonly he: "סרוק התאמה אישית תקופתית"; + readonly ja: "定期的にカスタマイズをスキャン"; + readonly ko: "주기적으로 사용자 설정 검색"; + readonly ru: "Сканировать настройки периодически"; + readonly zh: "定期扫描自定义设置"; + }; + readonly "Scan for Broken files": { + readonly def: "Scan for Broken files"; + readonly ja: "破損ファイルをスキャン"; + readonly ko: "손상된 파일 검사"; + readonly zh: "扫描损坏文件"; + readonly "zh-tw": "掃描損壞檔案"; + }; + readonly "Scan for hidden files before replication": { + readonly def: "Scan for hidden files before replication"; + readonly es: "Escanear archivos ocultos antes de replicar"; + readonly fr: "Analyser les fichiers cachés avant réplication"; + readonly he: "סרוק קבצים נסתרים לפני שכפול"; + readonly ja: "レプリケーション(複製)開始前に、隠しファイルのスキャンを行う"; + readonly ko: "복제 전 숨겨진 파일 검색"; + readonly ru: "Сканировать скрытые файлы перед репликацией"; + readonly zh: "复制前扫描隐藏文件"; + }; + readonly "Scan hidden files periodically": { + readonly def: "Scan hidden files periodically"; + readonly es: "Escanear archivos ocultos periódicamente"; + readonly fr: "Analyser les fichiers cachés périodiquement"; + readonly he: "סרוק קבצים נסתרים תקופתית"; + readonly ja: "定期的に隠しファイルのスキャンを行う"; + readonly ko: "주기적으로 숨겨진 파일 검색"; + readonly ru: "Сканировать скрытые файлы периодически"; + readonly zh: "定期扫描隐藏文件"; + }; + readonly "Scan the QR code displayed on an active device using this device's camera.": { + readonly def: "Scan the QR code displayed on an active device using this device's camera."; + readonly es: "Escanee con la cámara de este dispositivo el código QR mostrado en un dispositivo activo。"; + readonly ja: "稼働中の端末に表示された QR コードを、この端末のカメラで読み取ってください。"; + readonly ko: "이 장치의 카메라로 활성 장치에 표시된 QR 코드를 스캔하세요。"; + readonly ru: "Отсканируйте QR-код, показанный на активном устройстве, с помощью камеры этого устройства。"; + readonly zh: "使用当前设备的摄像头扫描另一台已在使用设备上显示的二维码。"; + readonly "zh-tw": "使用目前裝置的相機掃描另一台已在使用裝置上顯示的 QR Code。"; + }; + readonly "Schedule and Restart": { + readonly def: "Schedule and Restart"; + readonly es: "Programar y reiniciar"; + readonly ja: "予約して再起動"; + readonly ko: "예약 후 재시작"; + readonly ru: "Запланировать и перезапустить"; + readonly zh: "安排并重启"; + readonly "zh-tw": "排程後重新啟動"; + }; + readonly "Scram Switches": { + readonly def: "Scram Switches"; + readonly ja: "緊急対応スイッチ"; + readonly ko: "긴급 전환 스위치"; + readonly zh: "紧急开关"; + readonly "zh-tw": "緊急處置開關"; + }; + readonly "Scram!": { + readonly def: "Scram!"; + readonly es: "Medidas de emergencia"; + readonly ja: "緊急停止"; + readonly ko: "긴급 조치"; + readonly ru: "Экстренные меры"; + readonly zh: "紧急处置"; + readonly "zh-tw": "緊急處置"; + }; + readonly "Seconds, 0 to disable": { + readonly def: "Seconds, 0 to disable"; + readonly es: "Segundos, 0 para desactivar"; + readonly fr: "Secondes, 0 pour désactiver"; + readonly he: "שניות, 0 לביטול"; + readonly ja: "秒数、0で無効"; + readonly ko: "초 단위, 0으로 설정하면 비활성화"; + readonly ru: "Секунд, 0 для отключения"; + readonly zh: "秒,0为禁用"; + }; + readonly "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": { + readonly def: "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving."; + readonly es: "Segundos. Guardado en BD local se retrasará hasta este valor tras dejar de escribir/guardar"; + readonly fr: "Secondes. L'enregistrement dans la base locale sera différé de cette valeur après l'arrêt de la frappe ou de l'enregistrement."; + readonly he: "שניות. השמירה למסד הנתונים המקומי תתעכב בערך זה לאחר הפסקת הקלדה או שמירה."; + readonly ja: "秒。入力や保存を停止してからこの値の間、ローカルデータベースへの保存が遅延されます。"; + readonly ko: "초 단위입니다. 타이핑이나 저장을 중단한 후 이 시간동안 로컬 데이터베이스 저장이 지연됩니다."; + readonly ru: "Секунды. Сохранение в локальную базу данных будет отложено."; + readonly zh: "秒。在我们停止输入或保存后,保存到本地数据库将延迟此值 "; + }; + readonly "Secret Key": { + readonly def: "Secret Key"; + readonly es: "Clave secreta"; + readonly fr: "Clé secrète"; + readonly he: "מפתח סודי"; + readonly ja: "シークレットキー"; + readonly ko: "시크릿 키"; + readonly ru: "Секретный ключ"; + readonly zh: "Secret Key"; + }; + readonly "Select the database adapter to use.": { + readonly def: "Select the database adapter to use."; + readonly es: "Selecciona el adaptador de base de datos que se usará."; + readonly ja: "使用するデータベースアダプターを選択します。"; + readonly ko: "사용할 데이터베이스 어댑터를 선택합니다."; + readonly ru: "Выберите используемый адаптер базы данных."; + readonly zh: "选择要使用的数据库适配器。"; + readonly "zh-tw": "選擇要使用的資料庫適配器。"; + }; + readonly Send: { + readonly def: "Send"; + readonly es: "Enviar"; + readonly ja: "送信"; + readonly ko: "보내기"; + readonly ru: "Отправить"; + readonly zh: "发送"; + readonly "zh-tw": "傳送"; + }; + readonly "Send chunks": { + readonly def: "Send chunks"; + readonly es: "Enviar chunks"; + readonly ja: "チャンクを送信"; + readonly ko: "청크 보내기"; + readonly ru: "Отправить чанки"; + readonly zh: "发送 chunks"; + readonly "zh-tw": "傳送 chunks"; + }; + readonly "Server URI": { + readonly def: "Server URI"; + readonly es: "URI del servidor"; + readonly fr: "URI du serveur"; + readonly he: "כתובת שרת (URI)"; + readonly ja: "URI"; + readonly ko: "서버 URI"; + readonly ru: "URI сервера"; + readonly zh: "服务器 URI"; + }; + readonly "Setting.GenerateKeyPair.Desc": { + readonly def: "We have generated a key pair!\n\nNote: This key pair will never be shown again. Please save it in a safe place. If you have lost it, you need to generate a new key pair.\nNote 2: The public key is in spki format, and the Private key is in pkcs8 format. For the sake of convenience, newlines are converted to `\\n` in public key.\nNote 3: The public key should be configured in the remote database, and the private key should be configured in local devices.\n\n>[!FOR YOUR EYES ONLY]-\n>
\n>\n> ### Public Key\n> ```\n${public_key}\n> ```\n>\n> ### Private Key\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!Both for copying]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
\n\n"; + readonly es: "Hemos generado un par de claves.\n\nNota: Este par de claves no volverá a mostrarse. Guárdalo en un lugar seguro. Si lo pierdes, tendrás que generar uno nuevo.\nNota 2: La clave pública está en formato spki y la clave privada en formato pkcs8. Para mayor comodidad, los saltos de línea de la clave pública se convierten en `\\n`.\nNota 3: La clave pública debe configurarse en la base de datos remota y la clave privada en los dispositivos locales.\n\n>[!SOLO PARA TUS OJOS]-\n>
\n>\n> ### Clave pública\n> ```\n${public_key}\n> ```\n>\n> ### Clave privada\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!Ambas para copiar]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
"; + readonly fr: "Nous avons généré une paire de clés !\n\nNote : cette paire de clés ne sera plus jamais affichée. Veuillez la conserver dans un endroit sûr. Si vous la perdez, vous devrez générer une nouvelle paire.\nNote 2 : la clé publique est au format spki, et la clé privée au format pkcs8. Pour plus de commodité, les retours à la ligne sont convertis en `\\n` dans la clé publique.\nNote 3 : la clé publique doit être configurée dans la base distante, et la clé privée sur les appareils locaux.\n\n>[!POUR VOS YEUX SEULEMENT]-\n>
\n>\n> ### Clé publique\n> ```\n${public_key}\n> ```\n>\n> ### Clé privée\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!Les deux pour copier]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
\n\n"; + readonly he: "יצרנו זוג מפתחות!\n\nהערה: זוג מפתחות זה לא יוצג שוב. אנא שמור אותו במקום בטוח. אם אבד לך, יהיה צורך לייצר זוג מפתחות חדש.\nהערה 2: המפתח הציבורי הוא בפורמט spki, והמפתח הפרטי הוא בפורמט pkcs8. לנוחות, שורות חדשות ממוירות ל-`\\n` במפתח הציבורי.\nהערה 3: יש להגדיר את המפתח הציבורי במסד הנתונים המרוחד, ואת המפתח הפרטי במכשירים המקומיים.\n\n>[!FOR YOUR EYES ONLY]-\n>
\n>\n> ### מפתח ציבורי\n> ```\n${public_key}\n> ```\n>\n> ### מפתח פרטי\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!Both for copying]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
\n\n"; + readonly ja: "キーペアを生成しました!\n\n注意: このキーペアは再度表示されません。安全な場所に保存してください。紛失した場合は、新しいキーペアを生成する必要があります。\n注意2: 公開鍵はspki形式、秘密鍵はpkcs8形式です。利便性のため、公開鍵の改行は`\\n`に変換されています。\n注意3: 公開鍵はリモートデータベースに、秘密鍵はローカルデバイスに設定してください。\n\n>[!FOR YOUR EYES ONLY]-\n>
\n>\n> ### 公開鍵\n> ```\n${public_key}\n> ```\n>\n> ### 秘密鍵\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!Both for copying]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
\n\n"; + readonly ko: "키 페어를 생성했습니다!\n\n참고: 이 키 페어는 다시 표시되지 않습니다. 안전한 곳에 저장해 주세요. 분실하면 새 키 페어를 생성해야 합니다.\n참고 2: 공개 키는 spki 형식이고, 개인 키는 pkcs8 형식입니다. 편의상 공개 키의 줄 바꿈은 `\\n`으로 변환됩니다.\n참고 3: 공개 키는 원격 데이터베이스에서 구성되어야 하고, 개인 키는 로컬 기기에서 구성되어야 합니다.\n\n>[!FOR YOUR EYES ONLY]-\n>
\n>\n> ### 공개 키\n> ```\n${public_key}\n> ```\n>\n> ### 개인 키\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!Both for copying]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
\n\n\n"; + readonly ru: "Мы сгенерировали пару ключей!"; + readonly zh: "我们已经生成了一组密钥对!\n\n注意:这组密钥对之后将不会再次显示。请务必妥善保管;如果丢失,你需要重新生成新的密钥对。\n注意 2:公钥采用 spki 格式,私钥采用 pkcs8 格式。为方便复制,公钥中的换行会被转换为 `\\n`。\n注意 3:公钥应配置在远端数据库中,私钥应配置在本地设备上。\n\n>[!仅限本人查看]-\n>
\n>\n> ### 公钥\n> ```\n${public_key}\n> ```\n>\n> ### 私钥\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!整段复制]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
"; + readonly "zh-tw": "我們已產生新的金鑰對!\n\n注意:此金鑰對之後將不會再次顯示。請務必妥善保存;若遺失,必須重新產生新的金鑰對。\n注意 2:公鑰採用 spki 格式,私鑰採用 pkcs8 格式。為了方便複製,公鑰中的換行會轉換為 `\\n`。\n注意 3:公鑰應設定在遠端資料庫中,私鑰則應設定在本機裝置上。\n\n>[!僅供本人查看]-\n>
\n>\n> ### 公鑰\n> ```\n${public_key}\n> ```\n>\n> ### 私鑰\n> ```\n${private_key}\n> ```\n>\n>
\n\n>[!便於整段複製]-\n>\n>
\n>\n> ```\n${public_key}\n${private_key}\n> ```\n>\n>
"; + }; + readonly "Setting.GenerateKeyPair.Title": { + readonly def: "New key pair has been generated!"; + readonly es: "¡Se ha generado un nuevo par de claves!"; + readonly fr: "Une nouvelle paire de clés a été générée !"; + readonly he: "זוג מפתחות חדש נוצר!"; + readonly ja: "新しいキーペアが生成されました!"; + readonly ko: "새 키 페어가 생성되었습니다!"; + readonly ru: "Новая пара ключей сгенерирована!"; + readonly zh: "已生成新的密钥对!"; + readonly "zh-tw": "已產生新的金鑰對!"; + }; + readonly "Setting.TroubleShooting": { + readonly def: "TroubleShooting"; + readonly fr: "Dépannage"; + readonly he: "פתרון בעיות"; + readonly ja: "トラブルシューティング"; + readonly ko: "문제 해결"; + readonly ru: "Устранение неполадок"; + readonly zh: "故障排除"; + }; + readonly "Setting.TroubleShooting.Doctor": { + readonly def: "Setting Doctor"; + readonly fr: "Docteur des paramètres"; + readonly he: "Doctor הגדרות"; + readonly ja: "設定診断ツール"; + readonly ko: "설정 진단 마법사"; + readonly ru: "Диагностика настроек"; + readonly zh: "设置诊断"; + }; + readonly "Setting.TroubleShooting.Doctor.Desc": { + readonly def: "Detects non optimal settings. (Same as during migration)"; + readonly fr: "Détecte les paramètres non optimaux. (Identique à la migration)"; + readonly he: "מזהה הגדרות לא אופטימליות. (זהה לפעולה במהלך הגירה)"; + readonly ja: "最適でない設定を検出します。(マイグレーション時と同じ)"; + readonly ko: "최적화되지 않은 설정을 감지합니다. (데이터 구조 전환 시와 동일)"; + readonly ru: "Обнаруживает неоптимальные настройки."; + readonly zh: "检测系统中不合理的设置。(与迁移期间逻辑相同)"; + }; + readonly "Setting.TroubleShooting.ScanBrokenFiles": { + readonly def: "Scan for broken files"; + readonly fr: "Analyser les fichiers corrompus"; + readonly he: "סרוק קבצים פגומים"; + readonly ja: "破損ファイルのスキャン"; + readonly ko: "손상된 파일 검사"; + readonly ru: "Сканировать повреждённые файлы"; + readonly zh: "扫描损坏或异常的文件"; + }; + readonly "Setting.TroubleShooting.ScanBrokenFiles.Desc": { + readonly def: "Scans for files that are not stored correctly in the database."; + readonly fr: "Analyse les fichiers qui ne sont pas stockés correctement dans la base."; + readonly he: "סורק קבצים שלא נשמרו כהלכה במסד הנתונים."; + readonly ja: "データベースに正しく保存されていないファイルをスキャンします。"; + readonly ko: "데이터베이스에 올바르게 저장되지 않은 파일을 검사합니다."; + readonly ru: "Сканирует файлы, которые неправильно хранятся в базе данных."; + readonly zh: "扫描数据库中未正确存储的文件。"; + }; + readonly "SettingTab.Message.AskRebuild": { + readonly def: "Your changes require fetching from the remote database. Do you want to proceed?"; + readonly fr: "Vos modifications nécessitent une récupération depuis la base distante. Voulez-vous continuer ?"; + readonly he: "השינויים שלך מצריכים משיכה ממסד הנתונים המרוחד. האם להמשיך?"; + readonly ja: "変更にはリモートデータベースからのフェッチが必要です。続行しますか?"; + readonly ko: "변경 사항을 적용하려면 원격 데이터베이스에서 가져와야 합니다. 계속 진행하시겠습니까?"; + readonly ru: "Ваши изменения требуют загрузки из удалённой базы данных. Хотите продолжить?"; + readonly zh: "Your changes require fetching from the remote database. Do you want to proceed?"; + }; + readonly "Setup URI dialog cancelled.": { + readonly def: "Setup URI dialog cancelled."; + readonly ja: "Setup URI ダイアログはキャンセルされました。"; + readonly ko: "Setup URI 대화 상자가 취소되었습니다."; + readonly ru: "Диалог Setup URI был отменён."; + readonly zh: "Setup URI 对话框已取消。"; + readonly "zh-tw": "Setup URI 對話框已取消。"; + }; + readonly "Setup.Apply.Buttons.ApplyAndFetch": { + readonly def: "Apply and Fetch"; + readonly fr: "Appliquer et récupérer"; + readonly he: "החל ומשוך"; + readonly ja: "適用してフェッチ"; + readonly ru: "Применить и загрузить"; + readonly zh: "Apply and Fetch"; + }; + readonly "Setup.Apply.Buttons.ApplyAndMerge": { + readonly def: "Apply and Merge"; + readonly fr: "Appliquer et fusionner"; + readonly he: "החל ומזג"; + readonly ja: "適用してマージ"; + readonly ru: "Применить и объединить"; + readonly zh: "Apply and Merge"; + }; + readonly "Setup.Apply.Buttons.ApplyAndRebuild": { + readonly def: "Apply and Rebuild"; + readonly fr: "Appliquer et reconstruire"; + readonly he: "החל ובנה מחדש"; + readonly ja: "適用して再構築"; + readonly ru: "Применить и перестроить"; + readonly zh: "Apply and Rebuild"; + }; + readonly "Setup.Apply.Buttons.Cancel": { + readonly def: "Discard and Cancel"; + readonly fr: "Abandonner et annuler"; + readonly he: "בטל ובטל"; + readonly ja: "破棄してキャンセル"; + readonly ru: "Отменить и отменить"; + readonly zh: "Discard and Cancel"; + }; + readonly "Setup.Apply.Buttons.OnlyApply": { + readonly def: "Only Apply"; + readonly fr: "Appliquer seulement"; + readonly he: "החל בלבד"; + readonly ja: "適用のみ"; + readonly ru: "Только применить"; + readonly zh: "Only Apply"; + }; + readonly "Setup.Apply.Message": { + readonly def: "The new configuration is ready. Let us proceed to apply it.\nThere are several ways to apply this:\n\n- Apply and Fetch\n Configure this device as a new client. After applying, synchronise from the remote server.\n- Apply and Merge\n Configure on a device that already has the file. It processes the local files and transfers the differences. Conflicts may arise.\n- Apply and Rebuild\n Rebuild the remote using local files. This is typically done if the server becomes corrupted or we wish to start from scratch.\n Other devices will be locked and required to re-fetch.\n- Only Apply\n Apply only. Conflicts may arise if a rebuild is required."; + readonly fr: "La nouvelle configuration est prête. Procédons à son application.\nPlusieurs manières de l'appliquer :\n\n- Appliquer et récupérer\n Configurer cet appareil comme nouveau client. Après application, synchroniser depuis le serveur distant.\n- Appliquer et fusionner\n Configurer sur un appareil qui possède déjà les fichiers. Traite les fichiers locaux et transfère les différences. Des conflits peuvent apparaître.\n- Appliquer et reconstruire\n Reconstruire le distant à partir des fichiers locaux. Typiquement effectué si le serveur est corrompu ou si l'on souhaite repartir de zéro.\n Les autres appareils seront verrouillés et devront refaire une récupération.\n- Appliquer seulement\n Appliquer uniquement. Des conflits peuvent apparaître si une reconstruction est nécessaire."; + readonly he: "התצורה החדשה מוכנה. בואו נמשיך להחיל אותה.\nישנן מספר דרכים להחיל זאת:\n\n- החל ומשוך\n הגדר מכשיר זה כלקוח חדש. לאחר ההחלה, סנכרן מהשרת המרוחד.\n- החל ומזג\n הגדר על מכשיר שכבר יש בו קבצים. מעבד קבצים מקומיים ומעביר הפרשים. עלולים\n לקום קונפליקטים.\n- החל ובנה מחדש\n בנה את השרת המרוחד מחדש תוך שימוש בקבצים מקומיים. נעשה בדרך כלל אם השרת\n מושחת או אם רוצים להתחיל מאפס. מכשירים אחרים יינעלו ויצטרכו למשוך מחדש.\n- החל בלבד\n החל בלבד. עלולים לקום קונפליקטים אם נדרשת בנייה מחדש."; + readonly ja: "新しい設定の準備ができました。適用に進みましょう。\n適用方法はいくつかあります:\n\n- 適用してフェッチ\n このデバイスを新しいクライアントとして設定します。適用後、リモートサーバーから同期します。\n- 適用してマージ\n 既にファイルがあるデバイスで設定します。ローカルファイルを処理し、差分を転送します。競合が発生する場合があります。\n- 適用して再構築\n ローカルファイルを使用してリモートを再構築します。これは通常、サーバーが破損した場合や最初からやり直したい場合に行います。\n 他のデバイスはロックされ、再フェッチが必要になります。\n- 適用のみ\n 適用のみを行います。再構築が必要な場合、競合が発生する可能性があります。"; + readonly ru: "Новая конфигурация готова. Есть несколько способов применить её."; + readonly zh: "The new configuration is ready. Let us proceed to apply it.\nThere are several ways to apply this:\n\n- Apply and Fetch\n Configure this device as a new client. After applying, synchronise from the remote server.\n- Apply and Merge\n Configure on a device that already has the file. It processes the local files and transfers the differences. Conflicts may arise.\n- Apply and Rebuild\n Rebuild the remote using local files. This is typically done if the server becomes corrupted or we wish to start from scratch.\n Other devices will be locked and required to re-fetch.\n- Only Apply\n Apply only. Conflicts may arise if a rebuild is required."; + }; + readonly "Setup.Apply.Title": { + readonly def: "Apply new configuration from the ${method}"; + readonly fr: "Appliquer la nouvelle configuration depuis ${method}"; + readonly he: "החל תצורה חדשה מה-${method}"; + readonly ja: "${method}からの新しい設定を適用"; + readonly ru: "Применить новую конфигурацию из method"; + readonly zh: "Apply new configuration from the ${method}"; + }; + readonly "Setup.Apply.WarningRebuildRecommended": { + readonly def: "NOTE: after adjusting the settings, it has been determined that a rebuild is required; Just Import is not recommended."; + readonly fr: "NOTE : après ajustement des paramètres, il a été déterminé qu'une reconstruction est requise ; un simple import n'est pas recommandé."; + readonly he: "שים לב: לאחר כוונון ההגדרות, נקבע שנדרשת בנייה מחדש; ייבוא בלבד אינו מומלץ."; + readonly ja: "注意: 設定の調整後、再構築が必要と判断されました。インポートのみは推奨されません。"; + readonly ru: "ПРИМЕЧАНИЕ: после настройки изменений определено, что требуется перестроение."; + readonly zh: "NOTE: after adjusting the settings, it has been determined that a rebuild is required; Just Import is not recommended."; + }; + readonly "Setup.Doctor.Buttons.No": { + readonly def: "No, please use the settings in the URI as is"; + readonly fr: "Non, utiliser les paramètres de l'URI tels quels"; + readonly he: "לא, אנא השתמש בהגדרות ה-URI כפי שהן"; + readonly ja: "いいえ、URIの設定をそのまま使用"; + readonly ru: "Нет, использовать настройки из URI как есть"; + readonly zh: "No, please use the settings in the URI as is"; + }; + readonly "Setup.Doctor.Buttons.Yes": { + readonly def: "Yes, please consult the doctor"; + readonly fr: "Oui, consulter le docteur"; + readonly he: "כן, אנא יעץ ל-Doctor"; + readonly ja: "はい、診断ツールに相談する"; + readonly ru: "Да, пожалуйста, запустить диагностику"; + readonly zh: "Yes, please consult the doctor"; + }; + readonly "Setup.Doctor.Message": { + readonly def: "Self-hosted LiveSync has gradually become longer in history and some recommended settings have changed.\n\nNow, setup is a very good time to do this.\n\nDo you want to run Doctor to check if the imported settings are optimal compared to the latest state?"; + readonly fr: "Self-hosted LiveSync s'est progressivement étoffé et certains paramètres recommandés ont évolué.\n\nLa configuration est un bon moment pour le faire.\n\nVoulez-vous lancer le Docteur pour vérifier si les paramètres importés sont optimaux par rapport au dernier état ?"; + readonly he: "Self-hosted LiveSync הפך ארוך יותר בהיסטוריה שלו וחלק מההגדרות המומלצות השתנו.\n\nעכשיו, הגדרה היא זמן מצוין לכך.\n\nהאם ברצונך להפעיל את Doctor כדי לבדוק אם ההגדרות המיובאות אופטימליות בהשוואה למצב הנוכחי?"; + readonly ja: "Self-hosted LiveSyncは徐々に歴史が長くなり、一部の推奨設定が変更されています。\n\nセットアップは、これを行う非常に良い機会です。\n\nインポートされた設定が最新の状態と比較して最適かどうかを確認するために、診断ツールを実行しますか?"; + readonly ru: "Self-hosted LiveSync постепенно набрал историю и некоторые рекомендуемые настройки изменились."; + readonly zh: "Self-hosted LiveSync has gradually become longer in history and some recommended settings have changed.\n\nNow, setup is a very good time to do this.\n\nDo you want to run Doctor to check if the imported settings are optimal compared to the latest state?"; + }; + readonly "Setup.Doctor.Title": { + readonly def: "Do you want to consult the doctor?"; + readonly fr: "Voulez-vous consulter le docteur ?"; + readonly he: "האם ברצונך להתייעץ עם ה-Doctor?"; + readonly ja: "診断ツールに相談しますか?"; + readonly ru: "Хотите запустить диагностику?"; + readonly zh: "Do you want to consult the doctor?"; + }; + readonly "Setup.FetchRemoteConf.Buttons.Fetch": { + readonly def: "Yes, please fetch the configuration"; + readonly fr: "Oui, récupérer la configuration"; + readonly he: "כן, אנא משוך את התצורה"; + readonly ja: "はい、設定を取得"; + readonly ru: "Да, загрузить конфигурацию"; + readonly zh: "Yes, please fetch the configuration"; + }; + readonly "Setup.FetchRemoteConf.Buttons.Skip": { + readonly def: "No, please use the settings in the URI"; + readonly fr: "Non, utiliser les paramètres de l'URI"; + readonly he: "לא, אנא השתמש בהגדרות ב-URI"; + readonly ja: "いいえ、URIの設定を使用"; + readonly ru: "Нет, использовать настройки из URI"; + readonly zh: "No, please use the settings in the URI"; + }; + readonly "Setup.FetchRemoteConf.Message": { + readonly def: "If we have already synchronised once with another device, the remote database stores the suitable configuration values between the synchronised devices. The plug-in would like to retrieve them for robust configuration.\n\nHowever, we have to make sure the one thing. Are we currently in a situation where we can access the network safely and retrieve the settings?\n\nNote: Mostly, you are safe to do this, that your remote database is hosted with a SSL certificate, and your network is not compromised."; + readonly fr: "Si nous avons déjà synchronisé une fois avec un autre appareil, la base distante stocke les valeurs de configuration adaptées entre les appareils synchronisés. Le plug-in souhaiterait les récupérer pour une configuration robuste.\n\nMais il faut s'assurer d'une chose. Sommes-nous actuellement dans une situation où nous pouvons accéder au réseau en toute sécurité et récupérer les paramètres ?\n\nNote : le plus souvent, c'est sûr si votre base distante est hébergée avec un certificat SSL et si votre réseau n'est pas compromis."; + readonly he: "אם סנכרנו כבר פעם עם מכשיר אחר, מסד הנתונים המרוחד מאחסן ערכי תצורה מתאימים בין המכשירים המסונכרנים. הפלאגין ירצה לאחזר אותם לתצורה חזקה יותר.\n\nעם זאת, עלינו לוודא דבר אחד. האם אנחנו כרגע במצב שבו ניתן לגשת לרשת בבטחה ולאחזר את ההגדרות?\nהערה: ברוב המקרים, אתה בטוח לעשות זאת, כל עוד מסד הנתונים המרוחד שלך מאוחסן עם תעודת SSL, ורשתך אינה פגומה."; + readonly ja: "既に他のデバイスと同期したことがある場合、リモートデータベースには同期されたデバイス間の適切な設定値が保存されています。プラグインは堅牢な設定のためにそれらを取得したいと考えています。\n\nただし、1つ確認が必要です。現在、ネットワークに安全にアクセスして設定を取得できる状況ですか?\n\n注意: リモートデータベースがSSL証明書でホストされており、ネットワークが侵害されていなければ、ほとんどの場合安全に実行できます。"; + readonly ru: "Если мы уже синхронизировались с другим устройством, удалённая база данных хранит подходящие значения конфигурации."; + readonly zh: "If we have already synchronised once with another device, the remote database stores the suitable configuration values between the synchronised devices. The plug-in would like to retrieve them for robust configuration.\n\nHowever, we have to make sure the one thing. Are we currently in a situation where we can access the network safely and retrieve the settings?\n\nNote: Mostly, you are safe to do this, that your remote database is hosted with a SSL certificate, and your network is not compromised."; + }; + readonly "Setup.FetchRemoteConf.Title": { + readonly def: "Fetch configuration from remote database?"; + readonly fr: "Récupérer la configuration depuis la base distante ?"; + readonly he: "אחזר תצורה ממסד הנתונים המרוחד?"; + readonly ja: "リモートデータベースから設定を取得しますか?"; + readonly ru: "Загрузить конфигурацию с удалённой базы данных?"; + readonly zh: "Fetch configuration from remote database?"; + }; + readonly "Setup.QRCode": { + readonly def: "We have generated a QR code to transfer the settings. Please scan the QR code with your phone or other device.\nNote: The QR code is not encrypted, so be careful to open this.\n\n>[!FOR YOUR EYES ONLY]-\n>
${qr_image}
"; + readonly fr: "Nous avons généré un QR code pour transférer les paramètres. Scannez-le avec votre téléphone ou un autre appareil.\nNote : le QR code n'est pas chiffré, soyez prudent en l'affichant.\n\n>[!POUR VOS YEUX SEULEMENT]-\n>
${qr_image}
"; + readonly he: "יצרנו קוד QR להעברת ההגדרות. אנא סרוק את קוד ה-QR עם הטלפון או מכשיר אחר.\nהערה: קוד ה-QR אינו מוצפן, אז היה זהיר בפתיחתו.\n\n>[!FOR YOUR EYES ONLY]-\n>
${qr_image}
"; + readonly ja: "設定を転送するためのQRコードを生成しました。スマートフォンや他のデバイスでQRコードをスキャンしてください。\n注意: QRコードは暗号化されていないため、開く際は注意してください。\n\n>[!FOR YOUR EYES ONLY]-\n>
${qr_image}
"; + readonly ko: "설정을 전송하기 위한 QR 코드를 생성했습니다. 휴대폰이나 다른 기기로 QR 코드를 스캔해 주세요.\n참고: QR 코드는 암호화되지 않았으므로 열 때 주의하세요.\n\n>[!FOR YOUR EYES ONLY]-\n>
${qr_image}
"; + readonly ru: "Мы сгенерировали QR-код для передачи настроек. Отсканируйте QR-код телефоном."; + readonly zh: "We have generated a QR code to transfer the settings. Please scan the QR code with your phone or other device.\nNote: The QR code is not encrypted, so be careful to open this.\n\n>[!FOR YOUR EYES ONLY]-\n>
${qr_image}
"; + }; + readonly "Setup.RemoteE2EE.AdvancedTitle": { + readonly def: "Advanced"; + readonly es: "Avanzado"; + readonly ja: "詳細設定"; + readonly ko: "고급"; + readonly ru: "Дополнительно"; + readonly zh: "高级"; + readonly "zh-tw": "進階"; + }; + readonly "Setup.RemoteE2EE.AlgorithmWarning": { + readonly def: "Changing the encryption algorithm will prevent access to any data previously encrypted with a different algorithm. Ensure that all your devices are configured to use the same algorithm to maintain access to your data."; + readonly es: "Cambiar el algoritmo de cifrado impedirá el acceso a cualquier dato cifrado anteriormente con otro algoritmo. Asegúrate de que todos tus dispositivos estén configurados para usar el mismo algoritmo y así mantener el acceso a tus datos."; + readonly ja: "暗号化アルゴリズムを変更すると、別のアルゴリズムで暗号化された既存データにはアクセスできなくなります。すべての端末で同じアルゴリズムを使うよう設定し、データにアクセスできる状態を維持してください。"; + readonly ko: "암호화 알고리즘을 변경하면 다른 알고리즘으로 암호화된 기존 데이터에 접근할 수 없게 됩니다. 모든 기기에서 동일한 알고리즘을 사용하도록 설정해 데이터 접근성을 유지하세요."; + readonly ru: "Изменение алгоритма шифрования лишит доступа к данным, которые ранее были зашифрованы другим алгоритмом. Убедитесь, что все ваши устройства настроены на использование одного и того же алгоритма, чтобы сохранить доступ к данным."; + readonly zh: "更改加密算法会导致之前使用其他算法加密的数据无法访问。请确保所有设备都配置为使用同一算法,以保持对数据的访问能力。"; + readonly "zh-tw": "變更加密演算法後,先前以其他演算法加密的資料將無法再存取。請確認所有裝置都設定為使用相同演算法,以維持對資料的存取能力。"; + }; + readonly "Setup.RemoteE2EE.ButtonCancel": { + readonly def: "Cancel"; + readonly es: "Cancelar"; + readonly ja: "キャンセル"; + readonly ko: "취소"; + readonly ru: "Отмена"; + readonly zh: "取消"; + readonly "zh-tw": "取消"; + }; + readonly "Setup.RemoteE2EE.ButtonProceed": { + readonly def: "Proceed"; + readonly es: "Continuar"; + readonly ja: "進む"; + readonly ko: "진행"; + readonly ru: "Продолжить"; + readonly zh: "继续"; + readonly "zh-tw": "繼續"; + }; + readonly "Setup.RemoteE2EE.DefaultAlgorithmDesc": { + readonly def: "In most cases, you should stick with the default algorithm (${algorithm}). This setting is only required if you have an existing Vault encrypted in a different format."; + readonly es: "En la mayoría de los casos, debes mantener el algoritmo predeterminado (${algorithm}). Este ajuste solo es necesario si ya tienes un Vault cifrado con un formato diferente."; + readonly ja: "ほとんどの場合は、既定のアルゴリズム(${algorithm})をそのまま使用してください。この設定が必要になるのは、既存の Vault が別の形式で暗号化されている場合のみです。"; + readonly ko: "대부분의 경우 기본 알고리즘(${algorithm})을 그대로 사용하는 것이 좋습니다. 이 설정은 기존 Vault가 다른 형식으로 암호화되어 있는 경우에만 필요합니다."; + readonly ru: "В большинстве случаев следует оставить алгоритм по умолчанию (${algorithm}). Этот параметр нужен только в том случае, если у вас уже есть Vault, зашифрованный в другом формате."; + readonly zh: "在大多数情况下,你应继续使用默认算法(${algorithm})。只有当你已有一个采用不同格式加密的 Vault 时,才需要调整此设置。"; + readonly "zh-tw": "在大多數情況下,建議維持使用預設演算法(${algorithm})。只有當你現有的 Vault 是以不同格式加密時,才需要調整這項設定。"; + }; + readonly "Setup.RemoteE2EE.Guidance": { + readonly def: "Please configure your end-to-end encryption settings."; + readonly es: "Configura tus ajustes de cifrado de extremo a extremo."; + readonly ja: "エンドツーエンド暗号化の設定を行ってください。"; + readonly ko: "엔드투엔드 암호화 설정을 구성해 주세요."; + readonly ru: "Пожалуйста, настройте параметры сквозного шифрования."; + readonly zh: "请配置你的端到端加密设置。"; + readonly "zh-tw": "請設定你的端對端加密選項。"; + }; + readonly "Setup.RemoteE2EE.LabelEncrypt": { + readonly def: "End-to-End Encryption"; + readonly es: "Cifrado de extremo a extremo"; + readonly ja: "エンドツーエンド暗号化"; + readonly ko: "엔드투엔드 암호화"; + readonly ru: "Сквозное шифрование"; + readonly zh: "端到端加密"; + readonly "zh-tw": "端對端加密"; + }; + readonly "Setup.RemoteE2EE.LabelEncryptionAlgorithm": { + readonly def: "Encryption Algorithm"; + readonly es: "Algoritmo de cifrado"; + readonly ja: "暗号化アルゴリズム"; + readonly ko: "암호화 알고리즘"; + readonly ru: "Алгоритм шифрования"; + readonly zh: "加密算法"; + readonly "zh-tw": "加密演算法"; + }; + readonly "Setup.RemoteE2EE.LabelObfuscateProperties": { + readonly def: "Obfuscate Properties"; + readonly es: "Ofuscar propiedades"; + readonly ja: "プロパティを難読化"; + readonly ko: "속성 난독화"; + readonly ru: "Обфусцировать свойства"; + readonly zh: "混淆属性"; + readonly "zh-tw": "混淆屬性"; + }; + readonly "Setup.RemoteE2EE.MultiDestinationWarning": { + readonly def: "This setting must be the same even when connecting to multiple synchronisation destinations."; + readonly es: "Este ajuste debe ser el mismo incluso cuando te conectes a varios destinos de sincronización."; + readonly ja: "複数の同期先へ接続する場合でも、この設定は同一である必要があります。"; + readonly ko: "여러 동기화 대상에 연결하는 경우에도 이 설정은 동일해야 합니다."; + readonly ru: "Этот параметр должен быть одинаковым даже при подключении к нескольким направлениям синхронизации."; + readonly zh: "即使连接到多个同步目标,此设置也必须保持一致。"; + readonly "zh-tw": "即使連線到多個同步目標,這項設定也必須保持一致。"; + }; + readonly "Setup.RemoteE2EE.ObfuscatePropertiesDesc": { + readonly def: "Obfuscating properties (e.g., path of file, size, creation and modification dates) adds an additional layer of security by making it harder to identify the structure and names of your files and folders on the remote server. This helps protect your privacy and makes it more difficult for unauthorized users to infer information about your data."; + readonly es: "Ofuscar propiedades (por ejemplo, la ruta del archivo, el tamaño y las fechas de creación y modificación) añade una capa adicional de seguridad al dificultar la identificación de la estructura y los nombres de tus archivos y carpetas en el servidor remoto. Esto ayuda a proteger tu privacidad y dificulta que usuarios no autorizados deduzcan información sobre tus datos."; + readonly ja: "プロパティ(ファイルパス、サイズ、作成日時、更新日時など)を難読化すると、リモートサーバー上のファイルやフォルダーの構造や名前を特定しにくくできるため、追加の保護層になります。これによりプライバシーが守られ、権限のない第三者がデータに関する情報を推測しにくくなります。"; + readonly ko: "속성(예: 파일 경로, 크기, 생성일 및 수정일)을 난독화하면 원격 서버에서 파일과 폴더의 구조 및 이름을 식별하기 어렵게 만들어 보안을 한층 강화할 수 있습니다. 이는 개인 정보를 보호하고 권한 없는 사용자가 데이터에 관한 정보를 추론하기 어렵게 만듭니다."; + readonly ru: "Обфускация свойств (например, пути к файлу, размера, дат создания и изменения) добавляет дополнительный уровень защиты, затрудняя определение структуры и названий ваших файлов и папок на удалённом сервере. Это помогает защитить вашу конфиденциальность и усложняет для посторонних вывод информации о ваших данных."; + readonly zh: "混淆属性(例如文件路径、大小、创建和修改日期)可以增加一层额外保护,使远程服务器上的文件与文件夹结构及名称更难被识别。这有助于保护你的隐私,也让未授权用户更难推断你的数据相关信息。"; + readonly "zh-tw": "混淆屬性(例如檔案路徑、大小、建立時間與修改時間)可以額外增加一層安全保護,讓遠端伺服器上的檔案與資料夾結構及名稱更難被辨識。這有助於保護你的隱私,也讓未授權使用者更難推測你的資料資訊。"; + }; + readonly "Setup.RemoteE2EE.PassphraseValidationLine1": { + readonly def: "Please be aware that the End-to-End Encryption passphrase is not validated until the synchronisation process actually commences. This is a security measure designed to protect your data."; + readonly es: "Ten en cuenta que la frase de contraseña del cifrado de extremo a extremo no se valida hasta que el proceso de sincronización comienza realmente. Esta es una medida de seguridad diseñada para proteger tus datos."; + readonly ja: "エンドツーエンド暗号化のパスフレーズは、実際に同期処理が開始されるまで検証されない点にご注意ください。これはデータを保護するためのセキュリティ対策です。"; + readonly ko: "엔드투엔드 암호화 패스프레이즈는 실제 동기화가 시작되기 전까지 검증되지 않는다는 점에 유의하세요. 이것은 데이터를 보호하기 위한 보안 조치입니다."; + readonly ru: "Обратите внимание: парольная фраза для сквозного шифрования не проверяется до фактического начала процесса синхронизации. Это сделано в целях безопасности ваших данных."; + readonly zh: "请注意,在同步过程真正开始之前,端到端加密密码短语不会被校验。这是一项用于保护你数据的安全措施。"; + readonly "zh-tw": "請注意,端對端加密的密語要到同步程序實際開始時才會進行驗證。這是為了保護你資料而設計的安全措施。"; + }; + readonly "Setup.RemoteE2EE.PassphraseValidationLine2": { + readonly def: "Therefore, we ask that you exercise extreme caution when configuring server information manually. If an incorrect passphrase is entered, the data on the server will become corrupted. Please understand that this is intended behaviour."; + readonly es: "Por lo tanto, te pedimos que tengas muchísimo cuidado al configurar manualmente la información del servidor. Si introduces una frase de contraseña incorrecta, los datos del servidor se corromperán. Ten en cuenta que este comportamiento es intencionado."; + readonly ja: "そのため、サーバー情報を手動で設定する際は細心の注意を払ってください。誤ったパスフレーズを入力すると、サーバー上のデータが破損します。これは意図された動作ですので、あらかじめご理解ください。"; + readonly ko: "따라서 서버 정보를 수동으로 구성할 때는 각별히 주의해 주세요. 잘못된 패스프레이즈를 입력하면 서버의 데이터가 손상됩니다. 이는 의도된 동작이니 반드시 이해하고 진행해 주세요."; + readonly ru: "Поэтому при ручной настройке информации о сервере требуется предельная осторожность. Если будет введена неверная парольная фраза, данные на сервере будут повреждены. Пожалуйста, учтите, что это ожидаемое поведение."; + readonly zh: "因此,在手动配置服务器信息时请务必格外小心。如果输入了错误的密码短语,服务器上的数据将会损坏。请理解这属于预期行为。"; + readonly "zh-tw": "因此,在手動設定伺服器資訊時請務必格外小心。如果輸入了錯誤的密語,伺服器上的資料將會損毀。請理解這是系統的預期行為。"; + }; + readonly "Setup.RemoteE2EE.PlaceholderPassphrase": { + readonly def: "Enter your passphrase"; + readonly es: "Introduce tu frase de contraseña"; + readonly ja: "パスフレーズを入力してください"; + readonly ko: "패스프레이즈를 입력하세요"; + readonly ru: "Введите парольную фразу"; + readonly zh: "输入你的密码短语"; + readonly "zh-tw": "輸入你的密語"; + }; + readonly "Setup.RemoteE2EE.StronglyRecommendedLine1": { + readonly def: "Enabling end-to-end encryption ensures that your data is encrypted on your device before being sent to the remote server. This means that even if someone gains access to the server, they won't be able to read your data without the passphrase. Make sure to remember your passphrase, as it will be required to decrypt your data on other devices."; + readonly es: "Al habilitar el cifrado de extremo a extremo, tus datos se cifran en tu dispositivo antes de enviarse al servidor remoto. Esto significa que, incluso si alguien obtiene acceso al servidor, no podrá leer tus datos sin la frase de contraseña. Asegúrate de recordarla, ya que también será necesaria para descifrar tus datos en otros dispositivos."; + readonly ja: "エンドツーエンド暗号化を有効にすると、データはリモートサーバーへ送信される前にこの端末上で暗号化されます。つまり、たとえ誰かがサーバーへアクセスできても、パスフレーズがなければデータを読むことはできません。他の端末でデータを復号する際にも必要になるため、パスフレーズは必ず覚えておいてください。"; + readonly ko: "엔드투엔드 암호화를 활성화하면 데이터가 원격 서버로 전송되기 전에 이 기기에서 암호화됩니다. 즉, 누군가 서버에 접근하더라도 패스프레이즈 없이는 데이터를 읽을 수 없습니다. 다른 기기에서 데이터를 복호화할 때도 필요하므로 패스프레이즈를 반드시 기억해 두세요."; + readonly ru: "При включении сквозного шифрования ваши данные шифруются на устройстве до отправки на удалённый сервер. Это означает, что даже если кто-то получит доступ к серверу, он не сможет прочитать ваши данные без парольной фразы. Обязательно запомните парольную фразу, так как она потребуется для расшифровки данных на других устройствах."; + readonly zh: "启用端到端加密后,数据会先在你的设备上加密,再发送到远程服务器。这意味着即使有人获得了服务器访问权限,没有密码短语也无法读取你的数据。请务必记住你的密码短语,因为在其他设备上解密数据时也需要它。"; + readonly "zh-tw": "啟用端對端加密後,資料會先在你的裝置上完成加密,再傳送到遠端伺服器。這表示即使有人取得伺服器存取權,沒有密語也無法讀取你的資料。請務必記住你的密語,因為其他裝置在解密資料時也需要它。"; + }; + readonly "Setup.RemoteE2EE.StronglyRecommendedLine2": { + readonly def: "Also, please note that if you are using Peer-to-Peer synchronization, this configuration will be used when you switch to other methods and connect to a remote server in the future."; + readonly es: "Además, ten en cuenta que si estás usando sincronización Peer-to-Peer, esta configuración se utilizará cuando más adelante cambies a otros métodos y te conectes a un servidor remoto."; + readonly ja: "また、Peer-to-Peer 同期を使用している場合でも、将来ほかの方式へ切り替えてリモートサーバーへ接続するときには、この設定が使われます。"; + readonly ko: "또한 Peer-to-Peer 동기화를 사용 중이더라도, 나중에 다른 방식으로 전환하여 원격 서버에 연결하면 이 설정이 그대로 사용됩니다."; + readonly ru: "Также обратите внимание: если вы используете синхронизацию Peer-to-Peer, эта конфигурация будет использована, когда вы позже переключитесь на другие методы и подключитесь к удалённому серверу."; + readonly zh: "另外请注意,如果你正在使用 Peer-to-Peer 同步,当你以后切换到其他同步方式并连接远程服务器时,也会使用这组配置。"; + readonly "zh-tw": "另外請注意,即使你目前使用的是 Peer-to-Peer 同步,日後若切換到其他方式並連線到遠端伺服器時,也會沿用這組設定。"; + }; + readonly "Setup.RemoteE2EE.StronglyRecommendedTitle": { + readonly def: "Strongly Recommended"; + readonly es: "Muy recomendable"; + readonly ja: "強く推奨"; + readonly ko: "강력 권장"; + readonly ru: "Настоятельно рекомендуется"; + readonly zh: "强烈推荐"; + readonly "zh-tw": "強烈建議"; + }; + readonly "Setup.RemoteE2EE.Title": { + readonly def: "End-to-End Encryption"; + readonly es: "Cifrado de extremo a extremo"; + readonly ja: "エンドツーエンド暗号化"; + readonly ko: "엔드투엔드 암호화"; + readonly ru: "Сквозное шифрование"; + readonly zh: "端到端加密"; + readonly "zh-tw": "端對端加密"; + }; + readonly "Setup.ScanQRCode.ButtonClose": { + readonly def: "Close this dialog"; + readonly es: "Cerrar este diálogo"; + readonly ja: "このダイアログを閉じる"; + readonly ko: "이 대화 상자 닫기"; + readonly ru: "Закрыть это окно"; + readonly zh: "关闭此对话框"; + readonly "zh-tw": "關閉此對話框"; + }; + readonly "Setup.ScanQRCode.Guidance": { + readonly def: "Please follow the steps below to import settings from your existing device."; + readonly es: "Sigue los pasos de abajo para importar los ajustes desde tu dispositivo actual."; + readonly ja: "既存の端末から設定を取り込むには、以下の手順に従ってください。"; + readonly ko: "기존 기기에서 설정을 가져오려면 아래 단계를 따라 주세요."; + readonly ru: "Чтобы импортировать настройки с существующего устройства, выполните следующие шаги."; + readonly zh: "请按照以下步骤从现有设备导入设置。"; + readonly "zh-tw": "請依照以下步驟,從現有裝置匯入設定。"; + }; + readonly "Setup.ScanQRCode.Step1": { + readonly def: "On this device, please keep this Vault open."; + readonly es: "En este dispositivo, mantén este Vault abierto."; + readonly ja: "この端末では、この Vault を開いたままにしてください。"; + readonly ko: "이 기기에서는 이 Vault를 계속 열어 두세요."; + readonly ru: "На этом устройстве оставьте данный Vault открытым."; + readonly zh: "在这台设备上,请保持此 Vault 处于打开状态。"; + readonly "zh-tw": "在這台裝置上,請保持此 Vault 開啟。"; + }; + readonly "Setup.ScanQRCode.Step2": { + readonly def: "On the source device, open Obsidian."; + readonly es: "En el dispositivo de origen, abre Obsidian."; + readonly ja: "元の端末で Obsidian を開きます。"; + readonly ko: "원본 기기에서 Obsidian을 엽니다."; + readonly ru: "На исходном устройстве откройте Obsidian."; + readonly zh: "在源设备上打开 Obsidian。"; + readonly "zh-tw": "在來源裝置上開啟 Obsidian。"; + }; + readonly "Setup.ScanQRCode.Step3": { + readonly def: "On the source device, from the command palette, run the 'Show settings as a QR code' command."; + readonly es: "En el dispositivo de origen, ejecuta desde la paleta de comandos la orden \"Mostrar ajustes como código QR\"."; + readonly ja: "元の端末でコマンドパレットから「設定を QR コードとして表示」を実行します。"; + readonly ko: "원본 기기에서 명령 팔레트를 열고 \"설정을 QR 코드로 표시\" 명령을 실행합니다."; + readonly ru: "На исходном устройстве в палитре команд выполните команду «Показать настройки как QR-код»."; + readonly zh: "在源设备上,从命令面板运行“将设置显示为二维码”命令。"; + readonly "zh-tw": "在來源裝置上,從命令面板執行「將設定顯示為 QR 碼」命令。"; + }; + readonly "Setup.ScanQRCode.Step4": { + readonly def: "On this device, switch to the camera app or use a QR code scanner to scan the displayed QR code."; + readonly es: "En este dispositivo, cambia a la cámara o usa un escáner QR para escanear el código mostrado."; + readonly ja: "この端末でカメラアプリに切り替えるか QR コードスキャナーを使って、表示された QR コードを読み取ってください。"; + readonly ko: "이 기기에서 카메라 앱으로 전환하거나 QR 코드 스캐너를 사용해 표시된 QR 코드를 스캔하세요."; + readonly ru: "На этом устройстве откройте приложение камеры или используйте сканер QR-кодов, чтобы считать показанный QR-код."; + readonly zh: "在这台设备上,切换到相机应用或使用二维码扫描器扫描显示出的二维码。"; + readonly "zh-tw": "在這台裝置上切換到相機 App,或使用 QR 碼掃描器掃描顯示出的 QR 碼。"; + }; + readonly "Setup.ScanQRCode.Title": { + readonly def: "Scan QR Code"; + readonly es: "Escanear código QR"; + readonly ja: "QRコードをスキャン"; + readonly ko: "QR 코드 스캔"; + readonly ru: "Сканировать QR-код"; + readonly zh: "扫描二维码"; + readonly "zh-tw": "掃描 QR 碼"; + }; + readonly "Setup.ShowQRCode": { + readonly def: "Show QR code"; + readonly fr: "Afficher le QR code"; + readonly he: "הצג קוד QR"; + readonly ja: "QRコードを表示"; + readonly ko: "QR 코드 표시"; + readonly ru: "Показать QR код"; + readonly zh: "使用QR码"; + }; + readonly "Setup.ShowQRCode.Desc": { + readonly def: "Show QR code to transfer the settings."; + readonly fr: "Afficher le QR code pour transférer les paramètres."; + readonly he: "הצג קוד QR להעברת ההגדרות."; + readonly ja: "設定を転送するためのQRコードを表示します。"; + readonly ko: "설정을 전송하기 위한 QR 코드를 표시합니다."; + readonly ru: "Показать QR код для передачи настроек."; + readonly zh: "使用QR码来传递配置"; + }; + readonly "Setup.UseSetupURI.ButtonCancel": { + readonly def: "Cancel"; + readonly es: "Cancelar"; + readonly ja: "キャンセル"; + readonly ko: "취소"; + readonly ru: "Отмена"; + readonly zh: "取消"; + readonly "zh-tw": "取消"; + }; + readonly "Setup.UseSetupURI.ButtonProceed": { + readonly def: "Test Settings and Continue"; + readonly es: "Probar ajustes y continuar"; + readonly ja: "設定をテストして続行"; + readonly ko: "설정 테스트 후 계속"; + readonly ru: "Проверить настройки и продолжить"; + readonly zh: "测试设置并继续"; + readonly "zh-tw": "測試設定並繼續"; + }; + readonly "Setup.UseSetupURI.ErrorFailedToParse": { + readonly def: "Failed to parse the Setup URI. Please check the URI and passphrase."; + readonly es: "No se pudo procesar la URI de configuración. Revisa la URI y la frase de contraseña."; + readonly ja: "Setup URI を解析できませんでした。URI とパスフレーズを確認してください。"; + readonly ko: "Setup URI를 해석하지 못했습니다. URI와 패스프레이즈를 확인해 주세요."; + readonly ru: "Не удалось обработать Setup URI. Проверьте URI и парольную фразу."; + readonly zh: "无法解析 Setup URI,请检查 URI 和密码短语。"; + readonly "zh-tw": "無法解析 Setup URI,請檢查 URI 與密語。"; + }; + readonly "Setup.UseSetupURI.ErrorPassphraseRequired": { + readonly def: "Please enter the vault passphrase."; + readonly es: "Introduce la frase de contraseña del Vault."; + readonly ja: "Vault のパスフレーズを入力してください。"; + readonly ko: "Vault 패스프레이즈를 입력해 주세요."; + readonly ru: "Пожалуйста, введите парольную фразу Vault."; + readonly zh: "请输入 Vault 密码短语。"; + readonly "zh-tw": "請輸入 Vault 的密語。"; + }; + readonly "Setup.UseSetupURI.GuidanceLine1": { + readonly def: "Please enter the Setup URI that was generated during server installation or on another device, along with the vault passphrase."; + readonly es: "Introduce la URI de configuración que se generó durante la instalación del servidor o en otro dispositivo, junto con la frase de contraseña del Vault."; + readonly ja: "サーバーのセットアップ時または別の端末で生成された Setup URI と、Vault のパスフレーズを入力してください。"; + readonly ko: "서버 설치 중 또는 다른 기기에서 생성된 Setup URI와 Vault 패스프레이즈를 입력해 주세요."; + readonly ru: "Введите Setup URI, созданный во время установки сервера или на другом устройстве, а также парольную фразу Vault."; + readonly zh: "请输入在服务器安装期间或另一台设备上生成的 Setup URI,以及 Vault 密码短语。"; + readonly "zh-tw": "請輸入在伺服器安裝期間或其他裝置上產生的 Setup URI,以及 Vault 的密語。"; + }; + readonly "Setup.UseSetupURI.GuidanceLine2": { + readonly def: "Note that you can generate a new Setup URI by running the \"Copy settings as a new Setup URI\" command in the command palette."; + readonly es: "Ten en cuenta que puedes generar una nueva URI de configuración ejecutando el comando \"Copiar ajustes como nueva URI de configuración\" desde la paleta de comandos."; + readonly ja: "コマンドパレットで「設定を新しい Setup URI としてコピー」を実行すると、新しい Setup URI を生成できます。"; + readonly ko: "명령 팔레트에서 \"설정을 새 Setup URI로 복사\" 명령을 실행하면 새 Setup URI를 생성할 수 있습니다."; + readonly ru: "Новый Setup URI можно создать, выполнив в палитре команд команду «Скопировать настройки как новый Setup URI»."; + readonly zh: "你可以在命令面板中运行“将设置复制为新的 Setup URI”命令来生成新的 Setup URI。"; + readonly "zh-tw": "你可以在命令面板中執行「將設定複製為新的 Setup URI」命令來產生新的 Setup URI。"; + }; + readonly "Setup.UseSetupURI.InvalidInfo": { + readonly def: "The Setup URI is invalid. Please check it and try again."; + readonly es: "La URI de configuración no es válida. Revísala e inténtalo de nuevo."; + readonly ja: "Setup URI が無効です。内容を確認して再試行してください。"; + readonly ko: "Setup URI가 올바르지 않습니다. 확인한 뒤 다시 시도해 주세요."; + readonly ru: "Setup URI некорректен. Проверьте его и попробуйте снова."; + readonly zh: "Setup URI 无效,请检查后重试。"; + readonly "zh-tw": "Setup URI 無效,請檢查後再試一次。"; + }; + readonly "Setup.UseSetupURI.LabelPassphrase": { + readonly def: "Vault passphrase"; + readonly es: "Frase de contraseña del Vault"; + readonly ja: "Vault のパスフレーズ"; + readonly ko: "Vault 패스프레이즈"; + readonly ru: "Парольная фраза Vault"; + readonly zh: "Vault 密码短语"; + readonly "zh-tw": "Vault 密語"; + }; + readonly "Setup.UseSetupURI.LabelSetupURI": { + readonly def: "Setup URI"; + readonly es: "URI de configuración"; + readonly ja: "Setup URI"; + readonly ko: "Setup URI"; + readonly ru: "Setup URI"; + readonly zh: "Setup URI"; + readonly "zh-tw": "Setup URI"; + }; + readonly "Setup.UseSetupURI.PlaceholderPassphrase": { + readonly def: "Enter your vault passphrase"; + readonly es: "Introduce la frase de contraseña del Vault"; + readonly ja: "Vault のパスフレーズを入力してください"; + readonly ko: "Vault 패스프레이즈를 입력하세요"; + readonly ru: "Введите парольную фразу Vault"; + readonly zh: "输入 Vault 密码短语"; + readonly "zh-tw": "輸入 Vault 密語"; + }; + readonly "Setup.UseSetupURI.Title": { + readonly def: "Enter Setup URI"; + readonly es: "Introducir URI de configuración"; + readonly ja: "Setup URI を入力"; + readonly ko: "Setup URI 입력"; + readonly ru: "Ввести Setup URI"; + readonly zh: "输入 Setup URI"; + readonly "zh-tw": "輸入 Setup URI"; + }; + readonly "Setup.UseSetupURI.ValidInfo": { + readonly def: "The Setup URI is valid and ready to use."; + readonly es: "La URI de configuración es válida y está lista para usarse."; + readonly ja: "Setup URI は有効で、使用できます。"; + readonly ko: "Setup URI가 유효하며 사용할 준비가 되었습니다."; + readonly ru: "Setup URI корректен и готов к использованию."; + readonly zh: "Setup URI 有效,可以使用。"; + readonly "zh-tw": "Setup URI 有效,可以使用。"; + }; + readonly "Should we keep folders that don't have any files inside?": { + readonly def: "Should we keep folders that don't have any files inside?"; + readonly es: "¿Mantener carpetas vacías?"; + readonly fr: "Conserver les dossiers ne contenant aucun fichier ?"; + readonly he: "האם לשמור תיקיות שאין בהן קבצים?"; + readonly ja: "中にファイルがないフォルダーを保持しますか?"; + readonly ko: "내부에 파일이 없는 폴더를 유지하시겠습니까?"; + readonly ru: "Сохранять папки без файлов?"; + readonly zh: "我们是否应该保留内部没有任何文件的文件夹?"; + }; + readonly "Should we only check for conflicts when a file is opened?": { + readonly def: "Should we only check for conflicts when a file is opened?"; + readonly es: "¿Solo comprobar conflictos al abrir archivo?"; + readonly fr: "Ne vérifier les conflits qu'à l'ouverture d'un fichier ?"; + readonly he: "האם לבדוק קונפליקטים רק בעת פתיחת קובץ?"; + readonly ja: "ファイルを開いたときのみ競合をチェックしますか?"; + readonly ko: "파일을 열 때만 충돌을 확인하시겠습니까?"; + readonly ru: "Проверять конфликты только при открытии файла?"; + readonly zh: "我们是否应该仅在文件打开时检查冲突?"; + }; + readonly "Should we prompt you about conflicting files when a file is opened?": { + readonly def: "Should we prompt you about conflicting files when a file is opened?"; + readonly es: "¿Notificar sobre conflictos al abrir archivo?"; + readonly fr: "Vous demander au sujet des fichiers en conflit à l'ouverture d'un fichier ?"; + readonly he: "האם להציג בקשה לגבי קבצים מתנגשים בעת פתיחת קובץ?"; + readonly ja: "ファイルを開いたときに競合ファイルについて確認を求めますか?"; + readonly ko: "파일을 열 때 충돌하는 파일에 대해 알림을 표시하시겠습니까?"; + readonly ru: "Спрашивать о конфликтующих файлах при открытии файла?"; + readonly zh: "当文件打开时,是否提示冲突文件?"; + }; + readonly "Should we prompt you for every single merge, even if we can safely merge automatcially?": { + readonly def: "Should we prompt you for every single merge, even if we can safely merge automatcially?"; + readonly es: "¿Preguntar en cada fusión aunque sea automática?"; + readonly fr: "Vous demander pour chaque fusion, même si nous pouvons fusionner automatiquement en toute sécurité ?"; + readonly he: "האם להציג בקשת אישור לכל מיזוג יחיד, גם אם ניתן למזג בבטחה אוטומטית?"; + readonly ja: "自動的に安全にマージできる場合でも、すべてのマージについて確認を求めますか?"; + readonly ko: "안전하게 자동 병합할 수 있는 경우에도 모든 병합에 대해 알림을 받으시겠습니까?"; + readonly ru: "Спрашивать о каждом слиянии, даже если мы можем безопасно слить автоматически?"; + readonly zh: "即使我们可以安全地自动合并,是否也应该为每一次合并提示您?"; + }; + readonly "Show full banner": { + readonly def: "Show full banner"; + readonly es: "Mostrar banner completo"; + readonly ja: "完全なバナーを表示"; + readonly ko: "전체 배너 표시"; + readonly ru: "Показывать полный баннер"; + readonly zh: "显示完整横幅"; + readonly "zh-tw": "顯示完整橫幅"; + }; + readonly "Show history": { + readonly def: "Show history"; + readonly "zh-tw": "顯示歷程"; + }; + readonly "Show icon only": { + readonly def: "Show icon only"; + readonly zh: "仅显示图标"; + readonly "zh-tw": "僅顯示圖示"; + }; + readonly "Show only notifications": { + readonly def: "Show only notifications"; + readonly es: "Mostrar solo notificaciones"; + readonly fr: "N'afficher que les notifications"; + readonly he: "הצג התראות בלבד"; + readonly ja: "通知のみ表示"; + readonly ko: "알림만 표시"; + readonly ru: "Показывать только уведомления"; + readonly zh: "仅显示通知"; + }; + readonly "Show status as icons only": { + readonly def: "Show status as icons only"; + readonly es: "Mostrar estado solo con íconos"; + readonly fr: "N'afficher le statut que sous forme d'icônes"; + readonly he: "הצג סטטוס כאייקונים בלבד"; + readonly ja: "ステータス表示をアイコンのみにする"; + readonly ko: "아이콘으로만 상태 표시"; + readonly ru: "Показывать статус только иконками"; + readonly zh: "仅以图标显示状态"; + }; + readonly "Show status icon instead of file warnings banner": { + readonly def: "Show status icon instead of file warnings banner"; + readonly es: "Mostrar icono de estado en lugar del banner de advertencia de archivos"; + readonly fr: "Afficher l'icône de statut au lieu de la bannière d'avertissements"; + readonly he: "הצג אייקון סטטוס במקום פס אזהרות הקובץ"; + readonly ja: "ファイル警告バナーの代わりにステータスアイコンを表示"; + readonly ko: "파일 경고 배너 대신 상태 아이콘 표시"; + readonly ru: "Показывать иконку статуса вместо предупреждения о файлах"; + readonly zh: "显示状态图标,而非文件警告横幅"; + readonly "zh-tw": "以狀態圖示取代檔案警告橫幅"; + }; + readonly "Show status inside the editor": { + readonly def: "Show status inside the editor"; + readonly es: "Mostrar estado dentro del editor"; + readonly fr: "Afficher le statut dans l'éditeur"; + readonly he: "הצג סטטוס בתוך העורך"; + readonly ja: "ステータスをエディタ内に表示"; + readonly ko: "편집기 내부에 상태 표시"; + readonly ru: "Показывать статус внутри редактора"; + readonly zh: "在编辑器内显示状态"; + }; + readonly "Show status on the status bar": { + readonly def: "Show status on the status bar"; + readonly es: "Mostrar estado en la barra de estado"; + readonly fr: "Afficher le statut dans la barre d'état"; + readonly he: "הצג סטטוס בשורת המצב"; + readonly ja: "ステータスバーに、ステータスを表示"; + readonly ko: "상태 바에 상태 표시"; + readonly ru: "Показывать статус в строке состояния"; + readonly zh: "在状态栏上显示状态"; + }; + readonly "Show verbose log. Please enable if you report an issue.": { + readonly def: "Show verbose log. Please enable if you report an issue."; + readonly es: "Mostrar registro detallado. Actívelo si reporta un problema."; + readonly fr: "Afficher un journal verbeux. À activer si vous signalez un problème."; + readonly he: "הצג יומן מפורט. אנא הפעל אם אתה מדווח על בעיה."; + readonly ja: "エラー以外の詳細ログ項目も表示する。問題が発生した場合は有効にしてください。"; + readonly ko: "자세한 로그를 표시합니다. 문제를 신고하는 경우 활성화해 주세요."; + readonly ru: "Показывать подробный лог. Пожалуйста, включите при сообщении о проблеме."; + readonly zh: "显示详细日志。如果您报告问题,请启用此选项 "; + }; + readonly "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": { + readonly def: "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding."; + readonly ja: "一部のデバイスで進捗値が異なっています(最大: ${maxProgress}、最小: ${minProgress})。\nこれは一部のデバイスで同期が完了していない可能性を示しており、競合の原因になることがあります。続行する前に、すべてのデバイスが同期済みであることを確認することを強くおすすめします。"; + readonly ko: "일부 기기의 진행 값이 다릅니다(최대: ${maxProgress}, 최소: ${minProgress}).\n이는 일부 기기가 동기화를 완료하지 않았음을 의미할 수 있으며, 충돌로 이어질 수 있습니다. 계속 진행하기 전에 모든 기기가 동기화되었는지 반드시 확인하는 것을 강력히 권장합니다."; + readonly ru: "У некоторых устройств различаются значения прогресса (макс.: ${maxProgress}, мин.: ${minProgress}).\nЭто может означать, что некоторые устройства ещё не завершили синхронизацию, что может привести к конфликтам. Настоятельно рекомендуется перед продолжением убедиться, что все устройства синхронизированы."; + readonly zh: "某些设备的进度值不同(最大:${maxProgress},最小:${minProgress})。\n这可能表示某些设备尚未完成同步,从而可能引发冲突。强烈建议在继续之前先确认所有设备都已同步。"; + readonly "zh-tw": "某些裝置的進度值不同(最大:${maxProgress},最小:${minProgress})。\n這可能表示某些裝置尚未完成同步,進而可能導致衝突。強烈建議在繼續之前先確認所有裝置都已同步。"; + }; + readonly "Starts synchronisation when a file is saved.": { + readonly def: "Starts synchronisation when a file is saved."; + readonly es: "Inicia sincronización al guardar un archivo"; + readonly fr: "Démarre la synchronisation à l'enregistrement d'un fichier."; + readonly he: "מתחיל סנכרון כאשר קובץ נשמר."; + readonly ja: "ファイルが保存されたときに同期を開始します。"; + readonly ko: "파일이 저장될 때 동기화를 시작합니다."; + readonly ru: "Запускать синхронизацию при сохранении файла."; + readonly zh: "当文件保存时启动同步 "; + }; + readonly "Stop reflecting database changes to storage files.": { + readonly def: "Stop reflecting database changes to storage files."; + readonly es: "Dejar de reflejar cambios de BD en archivos"; + readonly fr: "Arrêter de répercuter les modifications de la base vers les fichiers de stockage."; + readonly he: "הפסק לשקף שינויי מסד נתונים לקבצי אחסון."; + readonly ja: "データベースの変更をストレージファイルに反映させない"; + readonly ko: "데이터베이스 변경 사항을 스토리지 파일에 반영하는 것을 중단합니다."; + readonly ru: "Остановить отражение изменений базы данных в файлы хранилища."; + readonly zh: "停止将数据库更改反映到存储文件 "; + }; + readonly "Stop watching for file changes.": { + readonly def: "Stop watching for file changes."; + readonly es: "Dejar de monitorear cambios en archivos"; + readonly fr: "Arrêter la surveillance des modifications de fichiers."; + readonly he: "הפסק לעקוב אחר שינויי קבצים."; + readonly ja: "監視の停止"; + readonly ko: "파일 변경 사항 감시를 중단합니다."; + readonly ru: "Остановить отслеживание изменений файлов."; + readonly zh: "停止监视文件更改 "; + }; + readonly "Storage -> Database": { + readonly def: "Storage -> Database"; + readonly "zh-tw": "儲存空間 -> 資料庫"; + }; + readonly "Suppress notification of hidden files change": { + readonly def: "Suppress notification of hidden files change"; + readonly es: "Suprimir notificaciones de cambios en archivos ocultos"; + readonly fr: "Supprimer les notifications de modification des fichiers cachés"; + readonly he: "דחוק התראת שינוי קבצים נסתרים"; + readonly ja: "隠しファイルの変更通知を抑制"; + readonly ko: "숨겨진 파일 변경 알림 억제"; + readonly ru: "Подавлять уведомления об изменении скрытых файлов"; + readonly zh: "暂停隐藏文件更改的通知"; + }; + readonly "Suspend database reflecting": { + readonly def: "Suspend database reflecting"; + readonly es: "Suspender reflejo de base de datos"; + readonly fr: "Suspendre la répercussion dans la base"; + readonly he: "השהה שיקוף מסד נתונים"; + readonly ja: "データベース反映の一時停止"; + readonly ko: "데이터베이스 반영 일시 중단"; + readonly ru: "Приостановить отражение базы данных"; + readonly zh: "暂停数据库反映"; + }; + readonly "Suspend file watching": { + readonly def: "Suspend file watching"; + readonly es: "Suspender monitorización de archivos"; + readonly fr: "Suspendre la surveillance des fichiers"; + readonly he: "השהה מעקב קבצים"; + readonly ja: "監視の一時停止"; + readonly ko: "파일 감시 일시 중단"; + readonly ru: "Приостановить отслеживание файлов"; + readonly zh: "暂停文件监视"; + }; + readonly "Switch to IDB": { + readonly def: "Switch to IDB"; + readonly es: "Cambiar a IDB"; + readonly ja: "IDB に切り替える"; + readonly ko: "IDB로 전환"; + readonly ru: "Переключиться на IDB"; + readonly zh: "切换到 IDB"; + readonly "zh-tw": "切換至 IDB"; + }; + readonly "Switch to IndexedDB": { + readonly def: "Switch to IndexedDB"; + readonly es: "Cambiar a IndexedDB"; + readonly ja: "IndexedDB に切り替える"; + readonly ko: "IndexedDB로 전환"; + readonly ru: "Переключиться на IndexedDB"; + readonly zh: "切换到 IndexedDB"; + readonly "zh-tw": "切換至 IndexedDB"; + }; + readonly "Sync after merging file": { + readonly def: "Sync after merging file"; + readonly es: "Sincronizar tras fusionar archivo"; + readonly fr: "Synchroniser après fusion d'un fichier"; + readonly he: "סנכרן לאחר מיזוג קובץ"; + readonly ja: "ファイルがマージ(統合)された時に同期"; + readonly ko: "파일 병합 후 동기화"; + readonly ru: "Синхронизировать после слияния файла"; + readonly zh: "合并文件后同步"; + }; + readonly "Sync automatically after merging files": { + readonly def: "Sync automatically after merging files"; + readonly es: "Sincronizar automáticamente tras fusionar archivos"; + readonly fr: "Synchroniser automatiquement après fusion des fichiers"; + readonly he: "סנכרן אוטומטית לאחר מיזוג קבצים"; + readonly ja: "ファイルのマージ後に自動的に同期"; + readonly ko: "파일 병합 후 자동으로 동기화"; + readonly ru: "Синхронизировать автоматически после слияния файлов"; + readonly zh: "合并文件后自动同步"; + }; + readonly "Sync Mode": { + readonly def: "Sync Mode"; + readonly es: "Modo de sincronización"; + readonly fr: "Mode de synchronisation"; + readonly he: "מצב סנכרון"; + readonly ja: "同期モード"; + readonly ko: "동기화 모드"; + readonly ru: "Режим синхронизации"; + readonly zh: "同步模式"; + }; + readonly "Sync on Editor Save": { + readonly def: "Sync on Editor Save"; + readonly es: "Sincronizar al guardar en editor"; + readonly fr: "Synchroniser à l'enregistrement dans l'éditeur"; + readonly he: "סנכרן בשמירת עורך"; + readonly ja: "エディタでの保存時に、同期されます"; + readonly ko: "편집기 저장 시 동기화"; + readonly ru: "Синхронизация при сохранении в редакторе"; + readonly zh: "编辑器保存时同步"; + }; + readonly "Sync on File Open": { + readonly def: "Sync on File Open"; + readonly es: "Sincronizar al abrir archivo"; + readonly fr: "Synchroniser à l'ouverture d'un fichier"; + readonly he: "סנכרן בפתיחת קובץ"; + readonly ja: "ファイルを開いた時に同期"; + readonly ko: "파일 열기 시 동기화"; + readonly ru: "Синхронизация при открытии файла"; + readonly zh: "打开文件时同步"; + }; + readonly "Sync on Save": { + readonly def: "Sync on Save"; + readonly es: "Sincronizar al guardar"; + readonly fr: "Synchroniser à l'enregistrement"; + readonly he: "סנכרן בשמירה"; + readonly ja: "保存時に同期"; + readonly ko: "저장 시 동기화"; + readonly ru: "Синхронизация при сохранении"; + readonly zh: "保存时同步"; + }; + readonly "Sync on Startup": { + readonly def: "Sync on Startup"; + readonly es: "Sincronizar al iniciar"; + readonly fr: "Synchroniser au démarrage"; + readonly he: "סנכרן בהפעלה"; + readonly ja: "起動時同期"; + readonly ko: "시작 시 동기화"; + readonly ru: "Синхронизация при запуске"; + readonly zh: "启动时同步"; + }; + readonly "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": { + readonly def: "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage."; + readonly es: "Sincronización mediante archivos de registro. Debe haber configurado un almacenamiento de objetos compatible con S3/MinIO/R2。"; + readonly ja: "ジャーナルファイルを利用する同期方式です。S3/MinIO/R2 互換のオブジェクトストレージを事前に構成しておく必要があります。"; + readonly ko: "저널 파일을 활용하는 동기화 방식입니다. S3/MinIO/R2 호환 객체 스토리지를 미리 구성해야 합니다。"; + readonly ru: "Синхронизация с использованием файлов журнала. Необходимо заранее настроить объектное хранилище, совместимое с S3/MinIO/R2。"; + readonly zh: "通过日志文件进行同步。你需要事先部署好兼容 S3/MinIO/R2 的对象存储服务。"; + readonly "zh-tw": "透過日誌檔進行同步。你需要事先部署好相容 S3/MinIO/R2 的物件儲存服務。"; + }; + readonly "Synchronising files": { + readonly def: "Synchronising files"; + readonly es: "Archivos sincronizados"; + readonly ja: "同期するファイル"; + readonly ko: "동기화할 파일"; + readonly ru: "Синхронизируемые файлы"; + readonly zh: "同步文件"; + readonly "zh-tw": "同步中的檔案"; + }; + readonly Syncing: { + readonly def: "Syncing"; + readonly es: "Sincronización"; + readonly ja: "同期"; + readonly ko: "동기화"; + readonly ru: "Синхронизация"; + readonly zh: "同步中"; + readonly "zh-tw": "同步中"; + }; + readonly "Target patterns": { + readonly def: "Target patterns"; + readonly es: "Patrones objetivo"; + readonly ja: "対象パターン"; + readonly ko: "대상 패턴"; + readonly ru: "Целевые шаблоны"; + readonly zh: "目标模式"; + readonly "zh-tw": "目標模式"; + }; + readonly "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": { + readonly def: "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned."; + readonly es: "Solo pruebas - Resolver conflictos sincronizando copias nuevas (puede sobrescribir modificaciones)"; + readonly fr: "Test uniquement - Résout les conflits de fichiers en synchronisant les copies plus récentes, ce qui peut écraser des fichiers modifiés. Prudence."; + readonly he: "לבדיקה בלבד - פתור קונפליקטי קבצים על ידי סנכרון עותקים חדשים יותר של הקובץ, פעולה זו עלולה לדרוס קבצים שונו. היה מוזהר."; + readonly ja: "テスト用 - ファイルの新しいコピーを同期してファイル競合を解決します。これにより変更されたファイルが上書きされる可能性があります。注意してください。"; + readonly ko: "테스트 전용 - 파일의 새로운 사본을 동기화하여 파일 충돌을 해결하며, 수정된 파일을 덮어쓸 수 있습니다. 주의하세요."; + readonly ru: "Только для тестирования - разрешать конфликты файлов синхронизацией новых копий."; + readonly zh: "仅供测试 - 通过同步文件的较新副本来解决文件冲突,这可能会覆盖修改过的文件。请注意 "; + }; + readonly "The delay for consecutive on-demand fetches": { + readonly def: "The delay for consecutive on-demand fetches"; + readonly es: "Retraso entre obtenciones consecutivas"; + readonly fr: "Le délai entre récupérations consécutives à la demande"; + readonly he: "העיכוב עבור משיכות לפי דרישה עוקבות"; + readonly ja: "連続したオンデマンドフェッチの遅延"; + readonly ko: "연속 청크 요청 간 대기 시간"; + readonly ru: "Задержка для последовательных запросов по требованию"; + readonly zh: "连续按需获取的延迟"; + }; + readonly "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": { + readonly def: "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once."; + readonly ja: "次の承認済みノードにはノード情報がありません:\n- ${missingNodes}\n\nこれは、それらがしばらく接続されていないか、古いバージョンのままになっていることを示しています。\n可能であれば、まずすべてのデバイスを更新することをおすすめします。すでに使用していないデバイスがある場合は、リモートを一度ロックすることで承認済みノードをすべてクリアできます。"; + readonly ko: "다음 승인된 노드에는 노드 정보가 없습니다:\n- ${missingNodes}\n\n이는 해당 노드가 한동안 연결되지 않았거나 이전 버전에 머물러 있음을 의미합니다.\n가능하다면 먼저 모든 기기를 업데이트하는 것이 좋습니다. 더 이상 사용하지 않는 기기가 있다면 원격을 한 번 잠가 승인된 노드를 모두 정리할 수 있습니다."; + readonly ru: "Для следующих принятых узлов отсутствует информация об узле:\n- ${missingNodes}\n\nЭто означает, что они давно не подключались или остались на старой версии.\nПо возможности рекомендуется сначала обновить все устройства. Если у вас есть устройства, которые больше не используются, вы можете очистить список всех принятых узлов, один раз заблокировав удалённую базу."; + readonly zh: "以下已接受节点缺少节点信息:\n- ${missingNodes}\n\n这表示它们已有一段时间未连接,或仍停留在较旧版本。\n如有可能,建议先更新所有设备。如果有已不再使用的设备,可以先锁定一次远程端以清除全部已接受节点。"; + readonly "zh-tw": "以下已接受節點缺少節點資訊:\n- ${missingNodes}\n\n這表示它們已有一段時間未連線,或仍停留在較舊版本。\n如有可能,建議先更新所有裝置。如果有已不再使用的裝置,可以先鎖定一次遠端端以清除全部已接受節點。"; + }; + readonly "The Hash algorithm for chunk IDs": { + readonly def: "The Hash algorithm for chunk IDs"; + readonly es: "Algoritmo hash para IDs de chunks"; + readonly fr: "L'algorithme de hachage pour les identifiants de fragments"; + readonly he: "אלגוריתם Hash עבור מזהי נתחים"; + readonly ja: "チャンクIDのハッシュアルゴリズム"; + readonly ko: "청크 ID용 해시 알고리즘"; + readonly ru: "Хэш-алгоритм для ID чанков"; + readonly zh: "块 ID 的哈希算法(实验性)"; + }; + readonly "The IndexedDB adapter often offers superior performance in certain scenarios, but it has been found to cause memory leaks when used with LiveSync mode. When using LiveSync mode, please use IDB adapter instead.": { + readonly def: "The IndexedDB adapter often offers superior performance in certain scenarios, but it has been found to cause memory leaks when used with LiveSync mode. When using LiveSync mode, please use IDB adapter instead."; + readonly "zh-tw": "IndexedDB 適配器在某些情況下通常能提供較佳效能,但在 LiveSync 模式下已發現可能導致記憶體洩漏。使用 LiveSync 模式時,請改用 IDB 適配器。"; + }; + readonly "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": { + readonly def: "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks."; + readonly es: "Duración máxima para incubar chunks. Excedentes se independizan"; + readonly fr: "La durée maximale pendant laquelle les fragments peuvent être incubés dans le document. Les fragments dépassant cette période seront promus en fragments indépendants."; + readonly he: "משך הזמן המקסימלי שנתחים יכולים להישמר זמנית בתוך המסמך. נתחים שחורגים מתקופה זו יהפכו לנתחים עצמאיים."; + readonly ja: "ドキュメント内でチャンクを保持できる最大期間。この期間を超えたチャンクは独立したチャンクに昇格します。"; + readonly ko: "변경 기록이 문서에 함께 보관될 수 있는 최대 시간입니다. 초과 시 문서에서 분리되어 개별로 저장됩니다."; + readonly ru: "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks."; + readonly zh: "文档中可以孵化的数据块的最大持续时间。超过此时间的数据块将成为独立数据块 "; + }; + readonly "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": { + readonly def: "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks."; + readonly es: "Número máximo de chunks que pueden incubarse en el documento. Excedentes se independizan"; + readonly fr: "Le nombre maximum de fragments pouvant être incubés dans le document. Les fragments dépassant ce nombre seront immédiatement promus en fragments indépendants."; + readonly he: "המספר המקסימלי של נתחים שיכולים להישמר זמנית בתוך המסמך. נתחים שחורגים ממספר זה יהפכו מיד לנתחים עצמאיים."; + readonly ja: "ドキュメント内で保持できるチャンクの最大数。この数を超えたチャンクは即座に独立したチャンクに昇格します。"; + readonly ko: "문서 안에 임시로 보관할 수 있는 변경 기록의 최대 개수입니다. 이 수를 초과하면 즉시 독립된 청크로 분리되어 저장됩니다."; + readonly ru: "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks."; + readonly zh: "文档中可以孵化的数据块的最大数量。超过此数量的数据块将立即成为独立数据块 "; + }; + readonly "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": { + readonly def: "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks."; + readonly es: "Tamaño total máximo de chunks incubados. Excedentes se independizan"; + readonly fr: "La taille totale maximale des fragments pouvant être incubés dans le document. Les fragments dépassant cette taille seront immédiatement promus en fragments indépendants."; + readonly he: "הגודל הכולל המקסימלי של נתחים שיכולים להישמר זמנית בתוך המסמך. נתחים שחורגים מגודל זה יהפכו מיד לנתחים עצמאיים."; + readonly ja: "ドキュメント内で保持できるチャンクの最大合計サイズ。このサイズを超えたチャンクは即座に独立したチャンクに昇格します。"; + readonly ko: "문서 안에 임시로 보관할 수 있는 변경 기록의 전체 크기 제한입니다. 초과 시 자동으로 분리됩니다."; + readonly ru: "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks."; + readonly zh: "文档中可以孵化的数据块的最大总大小。超过此大小的数据块将立即成为独立数据块 "; + }; + readonly "The minimum interval for automatic synchronisation on event.": { + readonly def: "The minimum interval for automatic synchronisation on event."; + readonly fr: "L'intervalle minimum pour la synchronisation automatique sur événement."; + readonly he: "מרווח הזמן המינימלי לסנכרון אוטומטי על אירוע."; + readonly ja: "イベント発生時の自動同期における最小間隔です。"; + readonly ko: "이벤트 발생 시 자동 동기화의 최소 간격입니다."; + readonly ru: "Минимальный интервал автоматической синхронизации по событию."; + readonly zh: "基于事件自动同步的最小间隔。"; + readonly "zh-tw": "事件觸發自動同步的最小間隔。"; + }; + readonly "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": { + readonly def: "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer."; + readonly es: "Esta función permite la sincronización directa entre dispositivos. No requiere servidor, pero ambos dispositivos deben estar en línea al mismo tiempo para que la sincronización se produzca, y algunas funciones pueden ser limitadas. La conexión a Internet solo se necesita para la señalización (detección de pares), no para la transferencia de datos。"; + readonly ja: "この機能では端末同士を直接同期できます。サーバーは不要ですが、同期を行うには両端末が同時にオンラインである必要があり、一部機能は制限されます。インターネット接続はシグナリング(ピア検出)にのみ必要で、データ転送自体には使われません。"; + readonly ko: "이 기능은 장치 간 직접 동기화를 제공합니다. 서버는 필요 없지만 동기화가 이루어지려면 두 장치가 동시에 온라인 상태여야 하며 일부 기능은 제한될 수 있습니다. 인터넷 연결은 시그널링(피어 감지)에만 필요하며 데이터 전송 자체에는 필요하지 않습니다。"; + readonly ru: "Эта функция обеспечивает прямую синхронизацию между устройствами. Сервер не требуется, но для синхронизации оба устройства должны быть одновременно в сети, а некоторые функции могут быть ограничены. Подключение к Интернету нужно только для сигнализации (обнаружения пиров), а не для передачи данных。"; + readonly zh: "此功能可在设备之间直接同步,无需服务器;但同步时两台设备必须同时在线,且部分功能可能受限。互联网连接仅用于信令(发现对端),不用于数据传输。"; + readonly "zh-tw": "此功能可在裝置之間直接同步,無需伺服器;但同步時兩台裝置必須同時在線,且部分功能可能受限。網際網路連線僅用於訊號交換(偵測對端),不用於資料傳輸。"; + }; + readonly "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": { + readonly def: "This is an advanced option for users who do not have a URI or who wish to configure detailed settings."; + readonly es: "Esta es una opción avanzada para usuarios que no disponen de un URI o que desean configurar parámetros detallados。"; + readonly ja: "URI を持っていない場合や、詳細設定を手動で行いたいユーザー向けの上級者オプションです。"; + readonly ko: "URI가 없거나 세부 설정을 직접 구성하려는 사용자를 위한 고급 옵션입니다。"; + readonly ru: "Это расширенный вариант для пользователей, у которых нет URI или которые хотят вручную задать подробные параметры。"; + readonly zh: "这是面向没有 URI 或希望手动配置详细参数的高级选项。"; + readonly "zh-tw": "這是面向沒有 URI 或希望手動設定詳細參數的進階選項。"; + }; + readonly "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": { + readonly def: "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance."; + readonly es: "Este es el método de sincronización más adecuado para el diseño. Todas las funciones están disponibles. Debe tener configurada una instancia de CouchDB。"; + readonly ja: "この設計に最も適した同期方式です。すべての機能が利用できます。CouchDB インスタンスを事前に構成しておく必要があります。"; + readonly ko: "이 설계에 가장 적합한 동기화 방식입니다. 모든 기능을 사용할 수 있습니다. CouchDB 인스턴스를 미리 구성해야 합니다。"; + readonly ru: "Это наиболее подходящий для данной архитектуры способ синхронизации. Доступны все функции. Необходимо заранее развернуть экземпляр CouchDB。"; + readonly zh: "这是最符合当前设计的同步方式,所有功能均可用。你需要事先部署好 CouchDB 实例。"; + readonly "zh-tw": "這是最符合目前設計的同步方式,所有功能皆可使用。你需要事先部署好 CouchDB 實例。"; + }; + readonly "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": { + readonly def: "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again."; + readonly es: "Esta frase no se copia a otros dispositivos. Usará `Default` hasta reconfigurar"; + readonly fr: "Cette phrase secrète ne sera pas copiée vers un autre appareil. Elle sera définie à `Default` jusqu'à ce que vous la configuriez à nouveau."; + readonly he: "ביטוי סיסמה זה לא יועתק למכשיר אחר. הוא יוגדר ל-`Default` עד שתגדיר אותו שוב."; + readonly ja: "このパスフレーズは他のデバイスにコピーされません。再度設定するまで`Default`に設定されます。"; + readonly ko: "이 패스프레이즈는 다른 기기로 복사되지 않습니다. 다시 구성할 때까지 `기본값`으로 설정됩니다."; + readonly ru: "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again."; + readonly zh: "此密码不会复制到另一台设备。在您再次配置之前,它将设置为 `Default` "; + }; + readonly "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": { + readonly def: "This will recreate chunks for all files. If there were missing chunks, this may fix the errors."; + readonly es: "Esto recreará los fragmentos de todos los archivos. Si faltaban fragmentos, esto puede corregir los errores."; + readonly ja: "すべてのファイルについてチャンクを再作成します。欠損しているチャンクがあった場合、エラーが解消される可能性があります。"; + readonly ko: "모든 파일의 청크를 다시 생성합니다. 누락된 청크가 있었다면 이 작업으로 오류가 해결될 수 있습니다."; + readonly ru: "Это пересоздаст чанки для всех файлов. Если какие-то чанки отсутствовали, это может исправить ошибки."; + readonly zh: "这会为所有文件重新生成 chunks。如果之前存在缺失的 chunks,这可能修复相关错误。"; + readonly "zh-tw": "這會為所有檔案重新建立 chunks。若先前有遺失的 chunks,這可能修復相關錯誤。"; + }; + readonly "Transfer Tweak": { + readonly def: "Transfer Tweak"; + readonly es: "Ajustes de transferencia"; + readonly ja: "転送の調整"; + readonly ko: "전송 조정"; + readonly ru: "Настройки передачи"; + }; + readonly "TweakMismatchResolve.Action.DisableAutoAcceptCompatible": { + readonly def: "Disable auto-accept"; + }; + readonly "TweakMismatchResolve.Action.Dismiss": { + readonly def: "Dismiss"; + readonly fr: "Ignorer"; + readonly he: "דחה"; + readonly ja: "無視"; + readonly ko: "무시"; + readonly ru: "Отмена"; + readonly zh: "Dismiss"; + }; + readonly "TweakMismatchResolve.Action.EnableAutoAcceptCompatible": { + readonly def: "Enable auto-accept"; + }; + readonly "TweakMismatchResolve.Action.UseConfigured": { + readonly def: "Use configured settings"; + readonly fr: "Utiliser les paramètres configurés"; + readonly he: "השתמש בהגדרות המוגדרות"; + readonly ja: "設定済みの設定を使用"; + readonly ko: "구성된 설정 사용"; + readonly ru: "Использовать настроенные параметры"; + readonly zh: "Use configured settings"; + }; + readonly "TweakMismatchResolve.Action.UseMine": { + readonly def: "Update remote database settings"; + readonly fr: "Mettre à jour les paramètres de la base distante"; + readonly he: "עדכן הגדרות מסד הנתונים המרוחד"; + readonly ja: "リモートデータベースの設定を更新"; + readonly ko: "원격 데이터베이스 설정 업데이트"; + readonly ru: "Обновить настройки удалённой базы данных"; + readonly zh: "Update remote database settings"; + }; + readonly "TweakMismatchResolve.Action.UseMineAcceptIncompatible": { + readonly def: "Update remote database settings but keep as is"; + readonly fr: "Mettre à jour la base distante mais garder en l'état"; + readonly he: "עדכן הגדרות מסד הנתונים המרוחד אך השאר כפי שהוא"; + readonly ja: "リモートデータベースの設定を更新するがそのまま維持"; + readonly ko: "원격 데이터베이스 설정 업데이트하지만 그대로 유지"; + readonly ru: "Обновить настройки, но оставить как есть"; + readonly zh: "Update remote database settings but keep as is"; + }; + readonly "TweakMismatchResolve.Action.UseMineWithRebuild": { + readonly def: "Update remote database settings and rebuild again"; + readonly fr: "Mettre à jour la base distante et reconstruire"; + readonly he: "עדכן הגדרות מסד הנתונים המרוחד ובנה מחדש"; + readonly ja: "リモートデータベースの設定を更新して再構築"; + readonly ko: "원격 데이터베이스 설정 업데이트하고 다시 재구축"; + readonly ru: "Обновить настройки и перестроить снова"; + readonly zh: "Update remote database settings and rebuild again"; + }; + readonly "TweakMismatchResolve.Action.UseRemote": { + readonly def: "Apply settings to this device"; + readonly fr: "Appliquer les paramètres à cet appareil"; + readonly he: "החל הגדרות על מכשיר זה"; + readonly ja: "このデバイスに設定を適用"; + readonly ko: "이 기기에 설정 적용"; + readonly ru: "Применить настройки к этому устройству"; + readonly zh: "Apply settings to this device"; + }; + readonly "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": { + readonly def: "Apply settings to this device, but and ignore incompatibility"; + readonly fr: "Appliquer à cet appareil, mais ignorer l'incompatibilité"; + readonly he: "החל הגדרות על מכשיר זה, אך התעלם מאי-תאימות"; + readonly ja: "このデバイスに設定を適用し、非互換性を無視"; + readonly ko: "이 기기에 설정 적용하지만 호환성 문제 무시"; + readonly ru: "Применить настройки, но игнорировать несовместимость"; + readonly zh: "Apply settings to this device, but and ignore incompatibility"; + }; + readonly "TweakMismatchResolve.Action.UseRemoteWithRebuild": { + readonly def: "Apply settings to this device, and fetch again"; + readonly fr: "Appliquer à cet appareil et récupérer à nouveau"; + readonly he: "החל הגדרות על מכשיר זה ומשוך שוב"; + readonly ja: "このデバイスに設定を適用し、再フェッチ"; + readonly ko: "이 기기에 설정 적용하고 다시 가져오기"; + readonly ru: "Применить настройки и загрузить снова"; + readonly zh: "Apply settings to this device, and fetch again"; + }; + readonly "TweakMismatchResolve.Message.AutoAcceptCompatibleUndefined": { + readonly def: "\nIt appears that the settings differ for each device. You can now automatically apply compatible changes to these configurations.\nWould you like to enable this `auto-accept` setting?"; + }; + readonly "TweakMismatchResolve.Message.Main": { + readonly def: "\nThe settings in the remote database are as follows. These values are configured by other devices, which are synchronised with this device at least once.\n\nIf you want to use these settings, please select Use configured settings.\nIf you want to keep the settings of this device, please select Dismiss.\n\n${table}\n\n>[!TIP]\n> If you want to synchronise all settings, please use `Sync settings via markdown` after applying minimal configuration with this feature.\n\n${additionalMessage}"; + readonly fr: "\nLes paramètres de la base distante sont les suivants. Ces valeurs sont configurées par d'autres appareils, synchronisés au moins une fois avec celui-ci.\n\nPour utiliser ces paramètres, sélectionnez Utiliser les paramètres configurés.\nPour conserver les paramètres de cet appareil, sélectionnez Ignorer.\n\n${table}\n\n>[!ASTUCE]\n> Pour synchroniser tous les paramètres, utilisez « Synchroniser les paramètres via markdown » après application de la configuration minimale avec cette fonctionnalité.\n\n${additionalMessage}"; + readonly he: "\nההגדרות במסד הנתונים המרוחד הן כדלקמן. ערכים אלה הוגדרו על ידי מכשירים אחרים, אשר סונכרנו עם מכשיר זה לפחות פעם אחת.\n\nאם ברצונך להשתמש בהגדרות אלה, אנא בחר %{TweakMismatchResolve.Action.UseConfigured}.\nאם ברצונך לשמור את הגדרות מכשיר זה, אנא בחר %{TweakMismatchResolve.Action.Dismiss}.\n\n${table}\n\n>[!TIP]\n> אם ברצונך לסנכרן את כל ההגדרות, אנא השתמש ב-`סנכרון הגדרות דרך Markdown` לאחר החלת תצורה מינימלית עם תכונה זו.\n\n${additionalMessage}"; + readonly ja: "\nリモートデータベースの設定は以下の通りです。これらの値は、このデバイスと少なくとも1回同期された他のデバイスによって設定されています。\n\nこれらの設定を使用する場合は、設定済みの設定を使用を選択してください。\nこのデバイスの設定を維持する場合は、無視を選択してください。\n\n${table}\n\n>[!TIP]\n> すべての設定を同期したい場合は、この機能で最小限の設定を適用した後、`Sync settings via markdown`を使用してください。\n\n${additionalMessage}"; + readonly ko: "\n원격 데이터베이스의 설정은 다음과 같습니다. 이 값들은 이 기기와 최소 한 번 동기화된 다른 기기에서 구성된 것입니다.\n\n이 설정을 사용하려면 구성된 설정 사용를 선택해 주세요.\n이 기기의 설정을 유지하려면 무시를 선택해 주세요.\n\n${table}\n\n>[!TIP]\n> 모든 설정을 동기화하려면 이 기능으로 최소 구성을 적용한 후 `마크다운을 통한 설정 동기화`를 사용해 주세요.\n\n${additionalMessage}"; + readonly ru: "Настройки в удалённой базе данных следующие. Эти значения настроены другими устройствами."; + readonly zh: "\nThe settings in the remote database are as follows. These values are configured by other devices, which are synchronised with this device at least once.\n\nIf you want to use these settings, please select Use configured settings.\nIf you want to keep the settings of this device, please select Dismiss.\n\n${table}\n\n>[!TIP]\n> If you want to synchronise all settings, please use `Sync settings via markdown` after applying minimal configuration with this feature.\n\n${additionalMessage}"; + }; + readonly "TweakMismatchResolve.Message.MainTweakResolving": { + readonly def: "Your configuration has not been matched with the one on the remote server.\n\nFollowing configuration should be matched:\n\n${table}\n\nLet us know your decision.\n\n${additionalMessage}"; + readonly fr: "Votre configuration ne correspond pas à celle du serveur distant.\n\nLa configuration suivante devrait correspondre :\n\n${table}\n\nFaites-nous part de votre décision.\n\n${additionalMessage}"; + readonly he: "התצורה שלך אינה תואמת לזו שבשרת המרוחד.\n\nיש להתאים את התצורות הבאות:\n\n${table}\n\nאנא הודע לנו על החלטתך.\n\n${additionalMessage}"; + readonly ja: "設定がリモートサーバーの設定と一致しません。\n\n以下の設定が一致している必要があります:\n\n${table}\n\n判断をお知らせください。\n\n${additionalMessage}"; + readonly ko: "구성이 원격 서버의 것과 일치하지 않습니다.\n\n다음 구성이 일치해야 합니다:\n\n${table}\n\n결정을 알려주세요.\n\n${additionalMessage}"; + readonly ru: "Ваша конфигурация не совпадает с удалённым сервером."; + readonly zh: "Your configuration has not been matched with the one on the remote server.\n\nFollowing configuration should be matched:\n\n${table}\n\nLet us know your decision.\n\n${additionalMessage}"; + }; + readonly "TweakMismatchResolve.Message.mineUpdated": { + readonly def: "The device configuration have been adjusted."; + }; + readonly "TweakMismatchResolve.Message.remoteUpdated": { + readonly def: "The configuration stored remotely has been updated."; + }; + readonly "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": { + readonly def: "\n>[!NOTICE]\n> Some changes are compatible but may consume extra storage and transfer volumes. A rebuild is recommended. However, a rebuild may not be performed at present, but may be implemented in future maintenance.\n> ***Please ensure that you have time and are connected to a stable network to apply!***"; + readonly fr: "\n>[!AVIS]\n> Certains changements sont compatibles mais peuvent consommer du stockage et du trafic supplémentaires. Une reconstruction est recommandée. Cependant, elle peut ne pas être effectuée maintenant, mais pourra l'être lors d'une maintenance future.\n> ***Assurez-vous d'avoir du temps et une connexion stable pour appliquer !***"; + readonly he: "\n>[!NOTICE]\n> חלק מהשינויים תואמים אך עלולים לצרוך אחסון ותעבורה נוספים. מומלצת בנייה מחדש. עם זאת, ייתכן שבנייה מחדש לא תתבצע כעת, אך תיושם בתחזוקה עתידית.\n> ***ודא שיש לך זמן ושאתה מחובר לרשת יציבה לפני ההחלה!***"; + readonly ja: "\n>[!NOTICE]\n> 一部の変更は互換性がありますが、追加のストレージと転送量を消費する可能性があります。再構築をお勧めします。ただし、再構築は現時点では実行されない場合がありますが、将来のメンテナンスで実装される可能性があります。\n> ***適用には時間と安定したネットワーク接続が必要です!***"; + readonly ko: "\n>[!NOTICE]\n> 일부 변경사항은 호환 가능하지만 추가 스토리지 및 전송량을 소모할 수 있습니다. 재구축을 권장합니다. 하지만 현재 재구축을 수행하지 않더라도 향후 유지보수에서 구현될 수 있습니다.\n> ***시간적 여유가 있고 안정적인 네트워크에 연결된 상태에서 적용해 주세요!***"; + readonly ru: "Некоторые изменения совместимы, но могут потребовать дополнительного хранилища. Рекомендуется перестроение."; + readonly zh: "\n>[!NOTICE]\n> Some changes are compatible but may consume extra storage and transfer volumes. A rebuild is recommended. However, a rebuild may not be performed at present, but may be implemented in future maintenance.\n> ***Please ensure that you have time and are connected to a stable network to apply!***"; + }; + readonly "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": { + readonly def: "\n>[!WARNING]\n> Some remote configurations are not compatible with the local database of this device. Rebuilding the local database will be required.\n> ***Please ensure that you have time and are connected to a stable network to apply!***"; + readonly fr: "\n>[!AVERTISSEMENT]\n> Certaines configurations distantes ne sont pas compatibles avec la base locale de cet appareil. Une reconstruction de la base locale sera requise.\n> ***Assurez-vous d'avoir du temps et une connexion stable pour appliquer !***"; + readonly he: "\n>[!WARNING]\n> חלק מהתצורות המרוחקות אינן תואמות למסד הנתונים המקומי של מכשיר זה. נדרשת בנייה מחדש של מסד הנתונים המקומי.\n> ***ודא שיש לך זמן ושאתה מחובר לרשת יציבה לפני ההחלה!***"; + readonly ja: "\n>[!WARNING]\n> 一部のリモート設定はこのデバイスのローカルデータベースと互換性がありません。ローカルデータベースの再構築が必要です。\n> ***適用には時間と安定したネットワーク接続が必要です!***"; + readonly ko: "\n>[!WARNING]\n> 일부 원격 구성이 이 기기의 로컬 데이터베이스와 호환되지 않습니다. 로컬 데이터베이스 재구축이 필요합니다.\n> ***시간적 여유가 있고 안정적인 네트워크에 연결된 상태에서 적용해 주세요!***"; + readonly ru: "Некоторые удалённые конфигурации несовместимы с локальной базой данных. Требуется перестроение."; + readonly zh: "\n>[!WARNING]\n> Some remote configurations are not compatible with the local database of this device. Rebuilding the local database will be required.\n> ***Please ensure that you have time and are connected to a stable network to apply!***"; + }; + readonly "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": { + readonly def: "\n>[!NOTICE]\n> We have detected that some of the values are different to make incompatible the local database with the remote database.\n> Some changes are compatible but may consume extra storage and transfer volumes. A rebuild is recommended. However, a rebuild may not be performed at present, but may be implemented in future maintenance.\n> If you want to rebuild, it takes a few minutes or more. **Make sure it is safe to perform it now.**"; + readonly fr: "\n>[!AVIS]\n> Nous avons détecté que certaines valeurs diffèrent et rendent la base locale incompatible avec la base distante.\n> Certains changements sont compatibles mais peuvent consommer du stockage et du trafic supplémentaires. Une reconstruction est recommandée. Cependant, elle peut ne pas être effectuée maintenant, mais pourra l'être lors d'une maintenance future.\n> Si vous souhaitez reconstruire, cela prend quelques minutes ou plus. **Assurez-vous qu'il est sûr de le faire maintenant.**"; + readonly he: "\n>[!NOTICE]\n> זיהינו שחלק מהערכים שונים, מה שגורם לאי-תאימות בין מסד הנתונים המקומי למרוחד.\n> חלק מהשינויים תואמים אך עלולים לצרוך אחסון ותעבורה נוספים. מומלצת בנייה מחדש. עם זאת, ייתכן שבנייה מחדש לא תתבצע כעת, אך תיושם בתחזוקה עתידית.\n> אם ברצונך לבנות מחדש, הדבר ייקח כמה דקות או יותר. **ודא שבטוח לבצע זאת עכשיו.**"; + readonly ja: "\n>[!NOTICE]\n> ローカルデータベースとリモートデータベースの非互換性を引き起こす値の違いが検出されました。\n> 一部の変更は互換性がありますが、追加のストレージと転送量を消費する可能性があります。再構築をお勧めします。ただし、再構築は現時点では実行されない場合がありますが、将来のメンテナンスで実装される可能性があります。\n> 再構築を行う場合は数分以上かかります。**今実行しても安全か確認してください。**"; + readonly ko: "\n>[!NOTICE]\n> 로컬 데이터베이스와 원격 데이터베이스가 호환되지 않도록 만드는 값들이 다른 것을 감지했습니다.\n> 일부 변경사항은 호환 가능하지만 추가 스토리지 및 전송량을 소모할 수 있습니다. 재구축을 권장합니다. 하지만 현재 재구축을 수행하지 않더라도 향후 유지보수에서 구현될 수 있습니다.\n> 재구축을 원한다면 몇 분 이상 소요됩니다. **지금 수행해도 안전한지 확인해 주세요.**"; + readonly ru: "Обнаружены значения, несовместимые с удалённой базой данных. Рекомендуется перестроение."; + readonly zh: "\n>[!NOTICE]\n> We have detected that some of the values are different to make incompatible the local database with the remote database.\n> Some changes are compatible but may consume extra storage and transfer volumes. A rebuild is recommended. However, a rebuild may not be performed at present, but may be implemented in future maintenance.\n> If you want to rebuild, it takes a few minutes or more. **Make sure it is safe to perform it now.**"; + }; + readonly "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": { + readonly def: "\n>[!WARNING]\n> We have detected that some of the values are different to make incompatible the local database with the remote database.\n> Either local or remote rebuilds are required. Both of them takes a few minutes or more. **Make sure it is safe to perform it now.**"; + readonly fr: "\n>[!AVERTISSEMENT]\n> Nous avons détecté que certaines valeurs diffèrent et rendent la base locale incompatible avec la base distante.\n> Une reconstruction locale ou distante est nécessaire. L'une comme l'autre prend quelques minutes ou plus. **Assurez-vous qu'il est sûr de le faire maintenant.**"; + readonly he: "\n>[!WARNING]\n> זיהינו שחלק מהערכים שונים, מה שגורם לאי-תאימות בין מסד הנתונים המקומי למרוחד.\n> נדרשת בנייה מחדש של המסד המקומי או המרוחד. שניהם ייקחו כמה דקות או יותר. **ודא שבטוח לבצע זאת עכשיו.**"; + readonly ja: "\n>[!WARNING]\n> ローカルデータベースとリモートデータベースの非互換性を引き起こす値の違いが検出されました。\n> ローカルまたはリモートの再構築が必要です。どちらも数分以上かかります。**今実行しても安全か確認してください。**"; + readonly ko: "\n>[!WARNING]\n> 로컬 데이터베이스와 원격 데이터베이스가 호환되지 않도록 만드는 값들이 다른 것을 감지했습니다.\n> 로컬 또는 원격 재구축이 필요합니다. 둘 다 몇 분 이상 소요됩니다. **지금 수행해도 안전한지 확인해 주세요.**"; + readonly ru: "Обнаружены значения, несовместимые с удалённой базой данных. Требуется перестроение."; + readonly zh: "\n>[!WARNING]\n> We have detected that some of the values are different to make incompatible the local database with the remote database.\n> Either local or remote rebuilds are required. Both of them takes a few minutes or more. **Make sure it is safe to perform it now.**"; + }; + readonly "TweakMismatchResolve.Table": { + readonly def: "| Value name | This device | On Remote |\n|: --- |: ---- :|: ---- :|\n${rows}\n\n"; + readonly fr: "| Nom de la valeur | Cet appareil | Sur le distant |\n|: --- |: ---- :|: ---- :|\n${rows}\n\n"; + readonly he: "| שם ערך | מכשיר זה | מרוחד |\n|: --- |: ---- :|: ---- :|\n${rows}\n\n"; + readonly ja: "| 値の名前 | このデバイス | リモート |\n|: --- |: ---- :|: ---- :|\n${rows}\n\n"; + readonly ko: "| 값 이름 | 이 기기 | 원격 |\n|: --- |: ---- :|: ---- :|\n${rows}\n\n"; + readonly ru: "| Имя значения | Это устройство | На удалённом |\n|: --- |: ---- :|: ---- :|"; + readonly zh: "| Value name | This device | On Remote |\n|: --- |: ---- :|: ---- :|\n${rows}\n\n"; + }; + readonly "TweakMismatchResolve.Table.Row": { + readonly def: "| ${name} | ${self} | ${remote} |"; + readonly fr: "| ${name} | ${self} | ${remote} |"; + readonly he: "| ${name} | ${self} | ${remote} |"; + readonly ja: "| ${name} | ${self} | ${remote} |"; + readonly ko: "| ${name} | ${self} | ${remote} |"; + readonly ru: "| name | self | remote |"; + readonly zh: "| ${name} | ${self} | ${remote} |"; + }; + readonly "TweakMismatchResolve.Title": { + readonly def: "Configuration Mismatch Detected"; + readonly fr: "Incohérence de configuration détectée"; + readonly he: "זוהתה אי-התאמה בתצורה"; + readonly ja: "設定の不一致が検出されました"; + readonly ko: "구성 불일치 감지"; + readonly ru: "Обнаружено несоответствие конфигурации"; + readonly zh: "Configuration Mismatch Detected"; + }; + readonly "TweakMismatchResolve.Title.AutoAcceptCompatible": { + readonly def: "Auto-Accept Available"; + }; + readonly "TweakMismatchResolve.Title.TweakResolving": { + readonly def: "Configuration Mismatch Detected"; + readonly fr: "Incohérence de configuration détectée"; + readonly he: "זוהתה אי-התאמה בתצורה"; + readonly ja: "設定の不一致が検出されました"; + readonly ko: "구성 불일치 감지"; + readonly ru: "Обнаружено несоответствие конфигурации"; + readonly zh: "Configuration Mismatch Detected"; + }; + readonly "TweakMismatchResolve.Title.UseRemoteConfig": { + readonly def: "Use Remote Configuration"; + readonly fr: "Utiliser la configuration distante"; + readonly he: "השתמש בתצורה המרוחקת"; + readonly ja: "リモート設定を使用"; + readonly ko: "원격 구성 사용"; + readonly ru: "Использовать удалённую конфигурацию"; + readonly zh: "Use Remote Configuration"; + }; + readonly "Ui.Common.Signal.Caution": { + readonly def: "CAUTION"; + readonly zh: "注意"; + }; + readonly "Ui.Common.Signal.Danger": { + readonly def: "DANGER"; + readonly zh: "危险"; + }; + readonly "Ui.Common.Signal.Notice": { + readonly def: "NOTICE"; + readonly zh: "提示"; + }; + readonly "Ui.Common.Signal.Warning": { + readonly def: "WARNING"; + readonly zh: "警告"; + }; + readonly "Ui.Settings.Advanced.LocalDatabaseTweak": { + readonly def: "Local Database Tweak"; + readonly zh: "本地数据库调整"; + }; + readonly "Ui.Settings.Advanced.MemoryCache": { + readonly def: "Memory Cache"; + readonly zh: "内存缓存"; + }; + readonly "Ui.Settings.Advanced.TransferTweak": { + readonly def: "Transfer Tweak"; + readonly zh: "传输调整"; + }; + readonly "Ui.Settings.Common.Analyse": { + readonly def: "Analyse"; + readonly zh: "分析"; + }; + readonly "Ui.Settings.Common.Back": { + readonly def: "Back"; + readonly zh: "返回"; + }; + readonly "Ui.Settings.Common.Check": { + readonly def: "Check"; + readonly zh: "检查"; + }; + readonly "Ui.Settings.Common.Configure": { + readonly def: "Configure"; + readonly zh: "配置"; + }; + readonly "Ui.Settings.Common.Continue": { + readonly def: "Continue"; + readonly zh: "继续"; + }; + readonly "Ui.Settings.Common.Delete": { + readonly def: "Delete"; + readonly zh: "删除"; + }; + readonly "Ui.Settings.Common.Fetch": { + readonly def: "Fetch"; + readonly zh: "获取"; + }; + readonly "Ui.Settings.Common.Lock": { + readonly def: "Lock"; + readonly zh: "锁定"; + }; + readonly "Ui.Settings.Common.Merge": { + readonly def: "Merge"; + readonly zh: "合并"; + }; + readonly "Ui.Settings.Common.Open": { + readonly def: "Open"; + readonly zh: "打开"; + }; + readonly "Ui.Settings.Common.Overwrite": { + readonly def: "Overwrite"; + readonly zh: "覆盖"; + }; + readonly "Ui.Settings.Common.Perform": { + readonly def: "Perform"; + readonly zh: "执行"; + }; + readonly "Ui.Settings.Common.ResetAll": { + readonly def: "Reset all"; + readonly zh: "全部重置"; + }; + readonly "Ui.Settings.Common.ResolveAll": { + readonly def: "Resolve All"; + readonly zh: "全部解决"; + }; + readonly "Ui.Settings.Common.Scan": { + readonly def: "Scan"; + readonly zh: "扫描"; + }; + readonly "Ui.Settings.Common.Send": { + readonly def: "Send"; + readonly zh: "发送"; + }; + readonly "Ui.Settings.Common.Use": { + readonly def: "Use"; + readonly zh: "使用"; + }; + readonly "Ui.Settings.Common.VerifyAll": { + readonly def: "Verify all"; + readonly zh: "全部校验"; + }; + readonly "Ui.Settings.CustomizationSync.OpenDesc": { + readonly def: "Open the dialog"; + readonly zh: "打开此对话框"; + }; + readonly "Ui.Settings.CustomizationSync.Panel": { + readonly def: "Customization Sync"; + readonly zh: "自定义同步"; + }; + readonly "Ui.Settings.CustomizationSync.WarnChangeDeviceName": { + readonly def: "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name."; + readonly zh: "启用此功能时无法修改设备名称。请先关闭此功能,再修改设备名称。"; + }; + readonly "Ui.Settings.CustomizationSync.WarnSetDeviceName": { + readonly def: "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature."; + readonly zh: "请先设置用于标识此设备的设备名称。该名称应在你的设备之间保持唯一。未设置前无法启用此功能。"; + }; + readonly "Ui.Settings.Hatch.AnalyseDatabaseUsage": { + readonly def: "Analyse database usage"; + readonly zh: "分析数据库使用情况"; + }; + readonly "Ui.Settings.Hatch.AnalyseDatabaseUsageDesc": { + readonly def: "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like."; + readonly zh: "分析数据库使用情况,并生成 TSV 报告供你自行诊断。你可以将生成的报告粘贴到任意电子表格工具中查看。"; + }; + readonly "Ui.Settings.Hatch.BackToNonConfigured": { + readonly def: "Back to non-configured"; + readonly zh: "返回未配置状态"; + }; + readonly "Ui.Settings.Hatch.ConvertNonObfuscated": { + readonly def: "Check and convert non-path-obfuscated files"; + readonly zh: "检查并转换未进行路径混淆的文件"; + }; + readonly "Ui.Settings.Hatch.ConvertNonObfuscatedDesc": { + readonly def: "Check the local database for files that were stored without path obfuscation and convert them when needed."; + readonly zh: "检查本地数据库中未按路径混淆方式存储的文件,并在需要时将其转换为正确格式。"; + }; + readonly "Ui.Settings.Hatch.CopyIssueReport": { + readonly def: "Copy Report to clipboard"; + readonly zh: "复制报告到剪贴板"; + }; + readonly "Ui.Settings.Hatch.DatabaseLabel": { + readonly def: "Database: ${details}"; + readonly zh: "数据库:${details}"; + }; + readonly "Ui.Settings.Hatch.DatabaseToStorage": { + readonly def: "Database -> Storage"; + readonly zh: "数据库 -> 存储"; + }; + readonly "Ui.Settings.Hatch.DeleteCustomizationSyncData": { + readonly def: "Delete all customization sync data"; + readonly zh: "删除所有自定义同步数据"; + }; + readonly "Ui.Settings.Hatch.GeneratedReport": { + readonly def: "Generated report"; + readonly zh: "已生成的报告"; + }; + readonly "Ui.Settings.Hatch.Missing": { + readonly def: "Missing"; + readonly zh: "缺失"; + }; + readonly "Ui.Settings.Hatch.ModifiedSize": { + readonly def: "Modified: ${modified}, Size: ${size}"; + readonly zh: "修改时间:${modified},大小:${size}"; + }; + readonly "Ui.Settings.Hatch.ModifiedSizeActual": { + readonly def: "Modified: ${modified}, Size: ${size} (actual size: ${actualSize})"; + readonly zh: "修改时间:${modified},大小:${size}(实际大小:${actualSize})"; + }; + readonly "Ui.Settings.Hatch.PrepareIssueReport": { + readonly def: "Prepare the 'report' to create an issue"; + readonly zh: "准备用于提交问题的报告"; + }; + readonly "Ui.Settings.Hatch.RecoveryAndRepair": { + readonly def: "Recovery and Repair"; + readonly zh: "恢复与修复"; + }; + readonly "Ui.Settings.Hatch.RecreateAll": { + readonly def: "Recreate all"; + readonly zh: "全部重建"; + }; + readonly "Ui.Settings.Hatch.RecreateMissingChunks": { + readonly def: "Recreate missing chunks for all files"; + readonly zh: "为所有文件重新创建缺失的数据块"; + }; + readonly "Ui.Settings.Hatch.RecreateMissingChunksDesc": { + readonly def: "This will recreate chunks for all files. If there were missing chunks, this may fix the errors."; + readonly zh: "此操作会为所有文件重新创建数据块。如果存在缺失的数据块,可能会修复相关错误。"; + }; + readonly "Ui.Settings.Hatch.ResetPanel": { + readonly def: "Reset"; + readonly zh: "重置"; + }; + readonly "Ui.Settings.Hatch.ResetRemoteUsage": { + readonly def: "Reset notification threshold and check the remote database usage"; + readonly zh: "重置通知阈值并检查远程数据库使用情况"; + }; + readonly "Ui.Settings.Hatch.ResetRemoteUsageDesc": { + readonly def: "Reset the remote storage size threshold and check the remote storage size again."; + readonly zh: "重置远程存储大小阈值,并再次检查远程存储大小。"; + }; + readonly "Ui.Settings.Hatch.ResolveAllConflictedFiles": { + readonly def: "Resolve all conflicted files by the newer one"; + readonly zh: "使用较新的版本解决所有冲突文件"; + }; + readonly "Ui.Settings.Hatch.ResolveAllConflictedFilesDesc": { + readonly def: "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one."; + readonly zh: "使用较新的版本解决所有冲突文件。注意:此操作会覆盖较旧版本,且无法恢复被覆盖的内容。"; + }; + readonly "Ui.Settings.Hatch.RunDoctor": { + readonly def: "Run Doctor"; + readonly zh: "运行诊断"; + }; + readonly "Ui.Settings.Hatch.ScanBrokenFiles": { + readonly def: "Scan for broken files"; + readonly zh: "扫描损坏文件"; + }; + readonly "Ui.Settings.Hatch.ScramSwitches": { + readonly def: "Scram Switches"; + readonly zh: "紧急开关"; + }; + readonly "Ui.Settings.Hatch.ShowHistory": { + readonly def: "Show history"; + readonly zh: "查看历史"; + }; + readonly "Ui.Settings.Hatch.StorageLabel": { + readonly def: "Storage: ${details}"; + readonly zh: "存储:${details}"; + }; + readonly "Ui.Settings.Hatch.StorageToDatabase": { + readonly def: "Storage -> Database"; + readonly zh: "存储 -> 数据库"; + }; + readonly "Ui.Settings.Hatch.VerifyAndRepairAllFiles": { + readonly def: "Verify and repair all files"; + readonly zh: "校验并修复所有文件"; + }; + readonly "Ui.Settings.Hatch.VerifyAndRepairAllFilesDesc": { + readonly def: "Compare the content of files between the local database and storage. If they do not match, you will be asked which one to keep."; + readonly zh: "比较本地数据库与存储中的文件内容。如果内容不一致,系统会询问你保留哪一份。"; + }; + readonly "Ui.Settings.Maintenance.Cleanup": { + readonly def: "Perform cleanup"; + readonly zh: "执行清理"; + }; + readonly "Ui.Settings.Maintenance.CleanupDesc": { + readonly def: "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client."; + readonly zh: "丢弃所有非最新修订版本,以减少存储空间占用。此操作要求远程服务器和本地客户端都具备同等大小的可用空间。"; + }; + readonly "Ui.Settings.Maintenance.DeleteLocalDatabase": { + readonly def: "Delete local database to reset or uninstall Self-hosted LiveSync"; + readonly zh: "删除本地数据库以重置或卸载 Self-hosted LiveSync"; + }; + readonly "Ui.Settings.Maintenance.EmergencyRestart": { + readonly def: "Emergency restart"; + readonly zh: "紧急重启"; + }; + readonly "Ui.Settings.Maintenance.EmergencyRestartDesc": { + readonly def: "Disable all synchronisation and restart."; + readonly zh: "禁用所有同步并重新启动。"; + }; + readonly "Ui.Settings.Maintenance.FreshStartWipe": { + readonly def: "Fresh Start Wipe"; + readonly zh: "全新开始清空"; + }; + readonly "Ui.Settings.Maintenance.FreshStartWipeDesc": { + readonly def: "Delete all data on the remote server."; + readonly zh: "删除远程服务器上的所有数据。"; + }; + readonly "Ui.Settings.Maintenance.GarbageCollection": { + readonly def: "Garbage Collection V3 (Beta)"; + readonly zh: "垃圾回收 V3(测试版)"; + }; + readonly "Ui.Settings.Maintenance.GarbageCollectionAction": { + readonly def: "Perform Garbage Collection"; + readonly zh: "执行垃圾回收"; + }; + readonly "Ui.Settings.Maintenance.GarbageCollectionDesc": { + readonly def: "Perform Garbage Collection to remove unused chunks and reduce database size."; + readonly zh: "执行垃圾回收以移除未使用的数据块并减少数据库大小。"; + }; + readonly "Ui.Settings.Maintenance.LockServer": { + readonly def: "Lock Server"; + readonly zh: "锁定服务器"; + }; + readonly "Ui.Settings.Maintenance.LockServerDesc": { + readonly def: "Lock the remote server to prevent synchronisation with other devices."; + readonly zh: "锁定远程服务器,防止与其他设备继续同步。"; + }; + readonly "Ui.Settings.Maintenance.OverwriteRemote": { + readonly def: "Overwrite remote"; + readonly zh: "覆盖远程端"; + }; + readonly "Ui.Settings.Maintenance.OverwriteRemoteDesc": { + readonly def: "Overwrite remote with local DB and passphrase."; + readonly zh: "使用本地数据库和密码短语覆盖远程端数据。"; + }; + readonly "Ui.Settings.Maintenance.OverwriteServerData": { + readonly def: "Overwrite Server Data with This Device's Files"; + readonly zh: "用此设备的文件覆盖服务器数据"; + }; + readonly "Ui.Settings.Maintenance.OverwriteServerDataDesc": { + readonly def: "Rebuild the local and remote database with files from this device."; + readonly zh: "使用此设备上的文件重建本地和远程数据库。"; + }; + readonly "Ui.Settings.Maintenance.PurgeAllJournalCounter": { + readonly def: "Purge all journal counter"; + readonly zh: "清空全部日志计数器"; + }; + readonly "Ui.Settings.Maintenance.PurgeAllJournalCounterDesc": { + readonly def: "Purge all download and upload caches."; + readonly zh: "清空所有下载与上传缓存。"; + }; + readonly "Ui.Settings.Maintenance.RebuildingOperations": { + readonly def: "Rebuilding Operations (Remote Only)"; + readonly zh: "重建操作(仅远程端)"; + }; + readonly "Ui.Settings.Maintenance.Resend": { + readonly def: "Resend"; + readonly zh: "重新发送"; + }; + readonly "Ui.Settings.Maintenance.ResendDesc": { + readonly def: "Resend all chunks to the remote."; + readonly zh: "将所有数据块重新发送到远程端。"; + }; + readonly "Ui.Settings.Maintenance.Reset": { + readonly def: "Reset"; + readonly zh: "重置"; + }; + readonly "Ui.Settings.Maintenance.ResetAllJournalCounter": { + readonly def: "Reset all journal counter"; + readonly zh: "重置全部日志计数器"; + }; + readonly "Ui.Settings.Maintenance.ResetAllJournalCounterDesc": { + readonly def: "Initialise all journal history. On the next sync, every item will be received and sent again."; + readonly zh: "初始化全部日志历史。下次同步时,所有项目都会重新接收并重新发送。"; + }; + readonly "Ui.Settings.Maintenance.ResetJournalReceived": { + readonly def: "Reset journal received history"; + readonly zh: "重置日志接收历史"; + }; + readonly "Ui.Settings.Maintenance.ResetJournalReceivedDesc": { + readonly def: "Initialise journal received history. On the next sync, every item except those sent by this device will be downloaded again."; + readonly zh: "初始化日志接收历史。下次同步时,除当前设备发送的项目外,其余项目都会重新下载。"; + }; + readonly "Ui.Settings.Maintenance.ResetJournalSent": { + readonly def: "Reset journal sent history"; + readonly zh: "重置日志发送历史"; + }; + readonly "Ui.Settings.Maintenance.ResetJournalSentDesc": { + readonly def: "Initialise journal sent history. On the next sync, every item except those received by this device will be sent again."; + readonly zh: "初始化日志发送历史。下次同步时,除当前设备已接收的项目外,其余项目都会重新发送。"; + }; + readonly "Ui.Settings.Maintenance.ResetLocalSyncInfo": { + readonly def: "Reset Synchronisation information"; + readonly zh: "重置同步信息"; + }; + readonly "Ui.Settings.Maintenance.ResetLocalSyncInfoDesc": { + readonly def: "Restore or reconstruct local database from remote."; + readonly zh: "从远程端恢复或重建本地数据库。"; + }; + readonly "Ui.Settings.Maintenance.ResetReceived": { + readonly def: "Reset received"; + readonly zh: "重置接收记录"; + }; + readonly "Ui.Settings.Maintenance.ResetSentHistory": { + readonly def: "Reset sent history"; + readonly zh: "重置发送记录"; + }; + readonly "Ui.Settings.Maintenance.ResetThisDevice": { + readonly def: "Reset Synchronisation on This Device"; + readonly zh: "重置此设备上的同步状态"; + }; + readonly "Ui.Settings.Maintenance.ScheduleAndRestart": { + readonly def: "Schedule and Restart"; + readonly zh: "计划执行并重启"; + }; + readonly "Ui.Settings.Maintenance.Scram": { + readonly def: "Scram!"; + readonly zh: "紧急处理"; + }; + readonly "Ui.Settings.Maintenance.SendChunks": { + readonly def: "Send chunks"; + readonly zh: "发送数据块"; + }; + readonly "Ui.Settings.Maintenance.Syncing": { + readonly def: "Syncing"; + readonly zh: "同步"; + }; + readonly "Ui.Settings.Maintenance.WarningLockedReadyAction": { + readonly def: "I am ready, unlock the database"; + readonly zh: "我已准备好,立即解锁数据库"; + }; + readonly "Ui.Settings.Maintenance.WarningLockedReadyText": { + readonly def: "To prevent unwanted vault corruption, the remote database has been locked for synchronisation. (This device is marked as 'resolved'.) When all your devices are marked as 'resolved', unlock the database. This warning will continue to appear until replication confirms the device is resolved."; + readonly zh: "为防止意外的数据仓库损坏,远程数据库已被锁定,暂停同步。(此设备已被标记为“已确认”)当你的所有设备都标记为“已确认”后,再解锁数据库。在复制过程确认此设备已完成确认之前,此警告会持续显示。"; + }; + readonly "Ui.Settings.Maintenance.WarningLockedResolveAction": { + readonly def: "I have made a backup, mark this device as resolved"; + readonly zh: "我已完成备份,将此设备标记为“已确认”"; + }; + readonly "Ui.Settings.Maintenance.WarningLockedResolveText": { + readonly def: "The remote database is locked for synchronisation to prevent vault corruption because this device is not marked as 'resolved'. Please back up your vault, reset the local database, and select 'Mark this device as resolved'. This warning will persist until replication confirms the device is resolved."; + readonly zh: "为防止数据仓库损坏,由于此设备尚未标记为“已确认”,远程数据库已被锁定,暂停同步。请先备份你的仓库、重置本地数据库,然后选择“将此设备标记为已确认”。在复制过程确认此设备已完成确认之前,此警告会持续显示。"; + }; + readonly "Ui.Settings.Maintenance.WriteRedFlagAndRestart": { + readonly def: "Flag and restart"; + readonly zh: "标记并重启"; + }; + readonly "Ui.Settings.Patches.CompatibilityConflict": { + readonly def: "Compatibility (Conflict Behaviour)"; + readonly zh: "兼容性(冲突行为)"; + }; + readonly "Ui.Settings.Patches.CompatibilityDatabase": { + readonly def: "Compatibility (Database structure)"; + readonly zh: "兼容性(数据库结构)"; + }; + readonly "Ui.Settings.Patches.CompatibilityInternalApi": { + readonly def: "Compatibility (Internal API Usage)"; + readonly zh: "兼容性(内部 API 使用)"; + }; + readonly "Ui.Settings.Patches.CompatibilityMetadata": { + readonly def: "Compatibility (Metadata)"; + readonly zh: "兼容性(元数据)"; + }; + readonly "Ui.Settings.Patches.CompatibilityRemote": { + readonly def: "Compatibility (Remote Database)"; + readonly zh: "兼容性(远程数据库)"; + }; + readonly "Ui.Settings.Patches.CompatibilityTrouble": { + readonly def: "Compatibility (Trouble addressed)"; + readonly zh: "兼容性(已处理问题)"; + }; + readonly "Ui.Settings.Patches.CurrentAdapter": { + readonly def: "Current adapter: ${adapter}"; + readonly zh: "当前适配器:${adapter}"; + }; + readonly "Ui.Settings.Patches.DatabaseAdapter": { + readonly def: "Database Adapter"; + readonly zh: "数据库适配器"; + }; + readonly "Ui.Settings.Patches.DatabaseAdapterDesc": { + readonly def: "Select the database adapter to use."; + readonly zh: "选择要使用的数据库适配器。"; + }; + readonly "Ui.Settings.Patches.EdgeCaseBehaviour": { + readonly def: "Edge case addressing (Behaviour)"; + readonly zh: "边界情况处理(行为)"; + }; + readonly "Ui.Settings.Patches.EdgeCaseDatabase": { + readonly def: "Edge case addressing (Database)"; + readonly zh: "边界情况处理(数据库)"; + }; + readonly "Ui.Settings.Patches.EdgeCaseProcessing": { + readonly def: "Edge case addressing (Processing)"; + readonly zh: "边界情况处理(处理流程)"; + }; + readonly "Ui.Settings.Patches.IndexedDbWarning": { + readonly def: "The IndexedDB adapter often offers superior performance in certain scenarios, but it has been found to cause memory leaks when used with LiveSync mode. When using LiveSync mode, please use the IDB adapter instead."; + readonly zh: "IndexedDB 适配器在某些场景下通常具有更好的性能,但在 LiveSync 模式下已发现可能导致内存泄漏。使用 LiveSync 模式时,请改用 IDB 适配器。"; + }; + readonly "Ui.Settings.Patches.MigratingToIdb": { + readonly def: "Migrating all data to IDB..."; + readonly zh: "正在将所有数据迁移到 IDB..."; + }; + readonly "Ui.Settings.Patches.MigratingToIndexedDb": { + readonly def: "Migrating all data to IndexedDB..."; + readonly zh: "正在将所有数据迁移到 IndexedDB..."; + }; + readonly "Ui.Settings.Patches.MigrationIdbCompleted": { + readonly def: "Migration to IDB completed. Obsidian will be restarted with the new configuration immediately."; + readonly zh: "已完成迁移到 IDB。Obsidian 将立即使用新配置重新启动。"; + }; + readonly "Ui.Settings.Patches.MigrationIdbCompletedFollowUp": { + readonly def: "Migration to IDB completed. Please switch the adapter and restart Obsidian."; + readonly zh: "已完成迁移到 IDB。请切换适配器并重新启动 Obsidian。"; + }; + readonly "Ui.Settings.Patches.MigrationIndexedDbCompleted": { + readonly def: "Migration to IndexedDB completed. Obsidian will be restarted with the new configuration immediately."; + readonly zh: "已完成迁移到 IndexedDB。Obsidian 将立即使用新配置重新启动。"; + }; + readonly "Ui.Settings.Patches.MigrationIndexedDbCompletedFollowUp": { + readonly def: "Migration to IndexedDB completed. Please switch the adapter and restart Obsidian."; + readonly zh: "已完成迁移到 IndexedDB。请切换适配器并重新启动 Obsidian。"; + }; + readonly "Ui.Settings.Patches.MigrationWarning": { + readonly def: "Changing this setting requires migrating existing data, which may take some time, and restarting Obsidian. Please make sure to back up your data before proceeding."; + readonly zh: "修改此设置需要迁移现有数据(可能需要一些时间)并重新启动 Obsidian。请先备份你的数据后再继续。"; + }; + readonly "Ui.Settings.Patches.OperationToIdb": { + readonly def: "to IDB"; + readonly zh: "迁移到 IDB"; + }; + readonly "Ui.Settings.Patches.OperationToIndexedDb": { + readonly def: "to IndexedDB"; + readonly zh: "迁移到 IndexedDB"; + }; + readonly "Ui.Settings.Patches.Remediation": { + readonly def: "Remediation"; + readonly zh: "修正"; + }; + readonly "Ui.Settings.Patches.RemediationChanged": { + readonly def: "Remediation Setting Changed"; + readonly zh: "修正设置已更改"; + }; + readonly "Ui.Settings.Patches.RemediationNoLimit": { + readonly def: "No limit configured"; + readonly zh: "未设置限制"; + }; + readonly "Ui.Settings.Patches.RemediationRestarting": { + readonly def: "Remediation setting changed. Restarting Obsidian..."; + readonly zh: "修正设置已更改,正在重新启动 Obsidian..."; + }; + readonly "Ui.Settings.Patches.RemediationRestartLater": { + readonly def: "Later"; + readonly zh: "稍后"; + }; + readonly "Ui.Settings.Patches.RemediationRestartMessage": { + readonly def: "Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and the display may be inconsistent. Are you sure you want to restart now?"; + readonly zh: "强烈建议重新启动 Obsidian。在重启之前,部分更改可能不会生效,界面显示也可能不一致。确定要现在重启吗?"; + }; + readonly "Ui.Settings.Patches.RemediationRestartNow": { + readonly def: "Restart Now"; + readonly zh: "立即重启"; + }; + readonly "Ui.Settings.Patches.RemediationSuffixChanged": { + readonly def: "Suffix has been changed. Reopening database..."; + readonly zh: "后缀已更改,正在重新打开数据库..."; + }; + readonly "Ui.Settings.Patches.RemediationWithValue": { + readonly def: "Limit: ${date} (${timestamp})"; + readonly zh: "限制:${date}(${timestamp})"; + }; + readonly "Ui.Settings.Patches.RemoteDatabaseSunset": { + readonly def: "Remote Database Tweak (In sunset)"; + readonly zh: "远程数据库调整(即将弃用)"; + }; + readonly "Ui.Settings.Patches.SwitchToIDB": { + readonly def: "Switch to IDB"; + readonly zh: "切换到 IDB"; + }; + readonly "Ui.Settings.Patches.SwitchToIndexedDb": { + readonly def: "Switch to IndexedDB"; + readonly zh: "切换到 IndexedDB"; + }; + readonly "Ui.Settings.PowerUsers.ConfigurationEncryption": { + readonly def: "Configuration Encryption"; + readonly zh: "配置加密"; + }; + readonly "Ui.Settings.PowerUsers.ConnectionTweak": { + readonly def: "CouchDB Connection Tweak"; + readonly zh: "CouchDB 连接调整"; + }; + readonly "Ui.Settings.PowerUsers.ConnectionTweakDesc": { + readonly def: "If you reached the payload size limit when using IBM Cloudant, please decrease batch size and batch limit to a lower value."; + readonly zh: "如果你在使用 IBM Cloudant 时遇到负载大小限制,请将 batch size 和 batch limit 调低。"; + }; + readonly "Ui.Settings.PowerUsers.Default": { + readonly def: "Default"; + readonly zh: "默认"; + }; + readonly "Ui.Settings.PowerUsers.Developer": { + readonly def: "Developer"; + readonly zh: "开发者"; + }; + readonly "Ui.Settings.PowerUsers.EncryptSensitiveConfig": { + readonly def: "Encrypt sensitive configuration items"; + readonly zh: "加密敏感配置项"; + }; + readonly "Ui.Settings.PowerUsers.PromptPassphraseEveryLaunch": { + readonly def: "Ask for a passphrase at every launch"; + readonly zh: "每次启动时询问密码短语"; + }; + readonly "Ui.Settings.PowerUsers.UseCustomPassphrase": { + readonly def: "Use a custom passphrase"; + readonly zh: "使用自定义密码短语"; + }; + readonly "Ui.Settings.Remote.Activate": { + readonly def: "Activate"; + readonly zh: "启用"; + }; + readonly "Ui.Settings.Remote.ActiveSuffix": { + readonly def: " (Active)"; + readonly zh: "(当前启用)"; + }; + readonly "Ui.Settings.Remote.AddConnection": { + readonly def: "Add new connection"; + readonly zh: "新增连接"; + }; + readonly "Ui.Settings.Remote.AddRemoteDefaultName": { + readonly def: "New Remote"; + readonly zh: "新远程端"; + }; + readonly "Ui.Settings.Remote.ConfigureAndChangeRemote": { + readonly def: "Configure and change remote"; + readonly zh: "配置并切换远程端"; + }; + readonly "Ui.Settings.Remote.ConfigureE2EE": { + readonly def: "Configure E2EE"; + readonly zh: "配置端到端加密"; + }; + readonly "Ui.Settings.Remote.ConfigureRemote": { + readonly def: "Configure Remote"; + readonly zh: "配置远程端"; + }; + readonly "Ui.Settings.Remote.DeleteRemoteConfirm": { + readonly def: "Delete remote configuration '${name}'?"; + readonly zh: "确定要删除远程配置“${name}”吗?"; + }; + readonly "Ui.Settings.Remote.DeleteRemoteTitle": { + readonly def: "Delete Remote Configuration"; + readonly zh: "删除远程配置"; + }; + readonly "Ui.Settings.Remote.DisplayName": { + readonly def: "Display name"; + readonly zh: "显示名称"; + }; + readonly "Ui.Settings.Remote.DuplicateRemote": { + readonly def: "Duplicate remote"; + readonly zh: "复制远程配置"; + }; + readonly "Ui.Settings.Remote.DuplicateRemoteSuffix": { + readonly def: "${name} (Copy)"; + readonly zh: "${name}(副本)"; + }; + readonly "Ui.Settings.Remote.E2EEConfiguration": { + readonly def: "E2EE Configuration"; + readonly zh: "端到端加密配置"; + }; + readonly "Ui.Settings.Remote.Export": { + readonly def: "Export"; + readonly zh: "导出"; + }; + readonly "Ui.Settings.Remote.FetchRemoteSettings": { + readonly def: "Fetch remote settings"; + readonly zh: "获取远程设置"; + }; + readonly "Ui.Settings.Remote.ImportConnection": { + readonly def: "Import connection"; + readonly zh: "导入连接"; + }; + readonly "Ui.Settings.Remote.ImportConnectionPrompt": { + readonly def: "Paste a connection string"; + readonly zh: "粘贴连接字符串"; + }; + readonly "Ui.Settings.Remote.ImportedCouchDb": { + readonly def: "Imported CouchDB"; + readonly zh: "已导入的 CouchDB"; + }; + readonly "Ui.Settings.Remote.ImportedRemote": { + readonly def: "Remote"; + readonly zh: "远程端"; + }; + readonly "Ui.Settings.Remote.MoreActions": { + readonly def: "More actions"; + readonly zh: "更多操作"; + }; + readonly "Ui.Settings.Remote.PeerToPeerPanel": { + readonly def: "Peer-to-Peer Synchronisation"; + readonly zh: "点对点同步"; + }; + readonly "Ui.Settings.Remote.RemoteConfigurationPrefix": { + readonly def: "Remote configuration"; + readonly zh: "远程配置"; + }; + readonly "Ui.Settings.Remote.RemoteDatabases": { + readonly def: "Remote Databases"; + readonly zh: "远程数据库"; + }; + readonly "Ui.Settings.Remote.RemoteName": { + readonly def: "Remote name"; + readonly zh: "远程名称"; + }; + readonly "Ui.Settings.Remote.RemoteNameCouchDb": { + readonly def: "CouchDB ${host}"; + readonly zh: "CouchDB ${host}"; + }; + readonly "Ui.Settings.Remote.RemoteNameP2P": { + readonly def: "P2P ${room}"; + readonly zh: "P2P ${room}"; + }; + readonly "Ui.Settings.Remote.RemoteNameS3": { + readonly def: "S3 ${bucket}"; + readonly zh: "S3 ${bucket}"; + }; + readonly "Ui.Settings.Remote.Rename": { + readonly def: "Rename"; + readonly zh: "重命名"; + }; + readonly "Ui.Settings.Selector.AddDefaultPatterns": { + readonly def: "Add default patterns"; + readonly zh: "添加默认模式"; + }; + readonly "Ui.Settings.Selector.CrossPlatform": { + readonly def: "Cross-platform"; + readonly zh: "跨平台"; + }; + readonly "Ui.Settings.Selector.Default": { + readonly def: "Default"; + readonly zh: "默认"; + }; + readonly "Ui.Settings.Selector.HiddenFiles": { + readonly def: "Hidden Files"; + readonly zh: "隐藏文件"; + }; + readonly "Ui.Settings.Selector.IgnorePatterns": { + readonly def: "Ignore patterns"; + readonly zh: "忽略模式"; + }; + readonly "Ui.Settings.Selector.NonSynchronisingFiles": { + readonly def: "Non-Synchronising files"; + readonly zh: "不同步文件"; + }; + readonly "Ui.Settings.Selector.NonSynchronisingFilesDesc": { + readonly def: "(RegExp) If this is set, any changes to local and remote files that match this will be skipped."; + readonly zh: "(RegExp)如果设置了该项,则本地和远程中匹配这些规则的文件变更将被跳过。"; + }; + readonly "Ui.Settings.Selector.NormalFiles": { + readonly def: "Normal Files"; + readonly zh: "普通文件"; + }; + readonly "Ui.Settings.Selector.OverwritePatterns": { + readonly def: "Overwrite patterns"; + readonly zh: "覆盖模式"; + }; + readonly "Ui.Settings.Selector.OverwritePatternsDesc": { + readonly def: "Patterns to match files for overwriting instead of merging"; + readonly zh: "匹配后将执行覆盖而非合并的文件模式"; + }; + readonly "Ui.Settings.Selector.SynchronisingFiles": { + readonly def: "Synchronising files"; + readonly zh: "同步文件"; + }; + readonly "Ui.Settings.Selector.SynchronisingFilesDesc": { + readonly def: "(RegExp) Empty to sync all files. Set a regular expression filter to limit synchronised files."; + readonly zh: "(RegExp)留空则同步所有文件。可设置正则表达式以限制需要同步的文件。"; + }; + readonly "Ui.Settings.Selector.TargetPatterns": { + readonly def: "Target patterns"; + readonly zh: "目标模式"; + }; + readonly "Ui.Settings.Selector.TargetPatternsDesc": { + readonly def: "Patterns to match files for syncing"; + readonly zh: "用于匹配需要同步文件的模式"; + }; + readonly "Ui.Settings.Setup.RerunWizardButton": { + readonly def: "Rerun Wizard"; + readonly zh: "重新运行向导"; + }; + readonly "Ui.Settings.Setup.RerunWizardDesc": { + readonly def: "Rerun the onboarding wizard to set up Self-hosted LiveSync again."; + readonly zh: "重新运行引导向导,再次设置 Self-hosted LiveSync。"; + }; + readonly "Ui.Settings.Setup.RerunWizardName": { + readonly def: "Rerun Onboarding Wizard"; + readonly zh: "重新运行引导向导"; + }; + readonly "Ui.Settings.SyncSettings.Fetch": { + readonly def: "Fetch"; + readonly zh: "获取"; + }; + readonly "Ui.Settings.SyncSettings.Merge": { + readonly def: "Merge"; + readonly zh: "合并"; + }; + readonly "Ui.Settings.SyncSettings.Overwrite": { + readonly def: "Overwrite"; + readonly zh: "覆盖"; + }; + readonly "Ui.SetupWizard.Common.Back": { + readonly def: "No, please take me back"; + readonly zh: "不,带我返回"; + }; + readonly "Ui.SetupWizard.Common.Cancel": { + readonly def: "Cancel"; + readonly zh: "取消"; + }; + readonly "Ui.SetupWizard.Common.ProceedSelectOption": { + readonly def: "Please select an option to proceed"; + readonly zh: "请选择一个选项后继续"; + }; + readonly "Ui.SetupWizard.Intro.ExistingOption": { + readonly def: "I am adding a device to an existing synchronisation setup"; + readonly zh: "将此设备加入已有同步配置"; + }; + readonly "Ui.SetupWizard.Intro.ExistingOptionDesc": { + readonly def: "Select this if you are already using synchronisation on another computer or smartphone. Use this option to connect this device to that existing setup."; + readonly zh: "如果你已经在另一台电脑或手机上使用同步,请选择此项。此选项用于将当前设备连接到既有同步配置。"; + }; + readonly "Ui.SetupWizard.Intro.Guidance": { + readonly def: "We will now guide you through a few questions to simplify the synchronisation setup."; + readonly zh: "接下来我们会通过几个问题,帮助你更轻松地完成同步配置。"; + }; + readonly "Ui.SetupWizard.Intro.NewOption": { + readonly def: "I am setting this up for the first time"; + readonly zh: "首次设置同步"; + }; + readonly "Ui.SetupWizard.Intro.NewOptionDesc": { + readonly def: "Select this if you are configuring this device as the first synchronisation device."; + readonly zh: "如果你正把这台设备作为第一台同步设备进行配置,请选择此项。"; + }; + readonly "Ui.SetupWizard.Intro.ProceedExisting": { + readonly def: "Yes, I want to add this device to my existing synchronisation"; + readonly zh: "是的,我要将此设备加入现有同步"; + }; + readonly "Ui.SetupWizard.Intro.ProceedNew": { + readonly def: "Yes, I want to set up a new synchronisation"; + readonly zh: "是的,我要开始新的同步配置"; + }; + readonly "Ui.SetupWizard.Intro.Question": { + readonly def: "First, please select the option that best describes your current situation."; + readonly zh: "首先,请选择最符合你当前情况的选项。"; + }; + readonly "Ui.SetupWizard.Intro.Title": { + readonly def: "Welcome to Self-hosted LiveSync"; + readonly zh: "欢迎使用 Self-hosted LiveSync"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.CompatibleOption": { + readonly def: "The remote is already set up, and the configuration is compatible (or became compatible through this operation)."; + readonly zh: "远程端已配置完成,且当前配置兼容(或已通过本次操作变为兼容)。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.CompatibleOptionDesc": { + readonly def: "Unless you are certain, selecting this option is risky. It assumes the server configuration is compatible with this device. If that is not the case, data loss may occur. Please make sure you understand the consequences."; + readonly zh: "除非你非常确定,否则选择此项存在风险。它假定服务器配置与当前设备兼容。如果事实并非如此,可能会导致数据丢失。请确认你了解后果。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.ExistingOption": { + readonly def: "My remote server is already set up. I want to join this device."; + readonly zh: "远程服务器已经配置完成,我想让此设备加入同步。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.ExistingOptionDesc": { + readonly def: "Selecting this option will make this device join the existing server. You need to fetch the existing synchronisation data from the server to this device."; + readonly zh: "选择此项后,此设备会加入已有服务器。你需要将服务器上的现有同步数据获取到此设备。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.Guidance": { + readonly def: "The connection to the server has been configured successfully. As the next step, the local database, in other words the synchronisation information, must be rebuilt."; + readonly zh: "服务器连接已成功配置。下一步需要重建本地数据库,也就是同步状态信息。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.NewOption": { + readonly def: "I am setting up a new server for the first time / I want to reset my existing server."; + readonly zh: "我是第一次配置新服务器 / 我想重置现有服务器。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.NewOptionDesc": { + readonly def: "Selecting this option will initialise the server using the current data on this device. Any existing data on the server will be completely overwritten."; + readonly zh: "选择此项后,服务器会使用当前设备上的数据进行初始化。服务器上的现有数据将被完全覆盖。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.ProceedApplySettings": { + readonly def: "Apply the settings"; + readonly zh: "应用这些设置"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.ProceedNext": { + readonly def: "Proceed to the next step."; + readonly zh: "继续下一步"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.Question": { + readonly def: "Please select your situation."; + readonly zh: "请选择你的当前情况。"; + }; + readonly "Ui.SetupWizard.OutroAskUserMode.Title": { + readonly def: "Mostly Complete: Decision Required"; + readonly zh: "即将完成:还需要做出选择"; + }; + readonly "Ui.SetupWizard.OutroNewUser.GuidancePrimary": { + readonly def: "The connection to the server has been configured successfully. As the next step, the synchronisation data on the server will be built from the current data on this device."; + readonly zh: "服务器连接已成功配置。下一步将根据当前设备上的数据,在服务器端建立同步数据。"; + }; + readonly "Ui.SetupWizard.OutroNewUser.GuidanceWarning": { + readonly def: "After restarting, the data on this device will be uploaded to the server as the master copy. Please note that any unintended data currently on the server will be completely overwritten."; + readonly zh: "重启后,当前设备上的数据会作为主副本上传到服务器。请注意,服务器上现有的非预期数据将被完全覆盖。"; + }; + readonly "Ui.SetupWizard.OutroNewUser.Important": { + readonly def: "IMPORTANT"; + readonly zh: "重要"; + }; + readonly "Ui.SetupWizard.OutroNewUser.Proceed": { + readonly def: "Restart and Initialise Server"; + readonly zh: "重启并初始化服务器"; + }; + readonly "Ui.SetupWizard.OutroNewUser.Question": { + readonly def: "Please select the button below to restart and proceed to the final confirmation."; + readonly zh: "请选择下方按钮,重启并进入最终确认步骤。"; + }; + readonly "Ui.SetupWizard.OutroNewUser.Title": { + readonly def: "Setup Complete: Preparing to Initialise Server"; + readonly zh: "设置完成:准备初始化服务器"; + }; + readonly "Ui.SetupWizard.SelectExisting.Guidance": { + readonly def: "You are adding this device to an existing synchronisation setup."; + readonly zh: "你正在将此设备加入已有同步配置。"; + }; + readonly "Ui.SetupWizard.SelectExisting.ManualOption": { + readonly def: "Enter the server information manually"; + readonly zh: "手动输入服务器信息"; + }; + readonly "Ui.SetupWizard.SelectExisting.ManualOptionDesc": { + readonly def: "Configure the same server information as your other devices again manually. This is intended only for advanced users."; + readonly zh: "手动重新配置与你其他设备相同的服务器信息。此方式仅适用于高级用户。"; + }; + readonly "Ui.SetupWizard.SelectExisting.ProceedManual": { + readonly def: "I know my server details, let me enter them"; + readonly zh: "我知道服务器信息,让我手动输入"; + }; + readonly "Ui.SetupWizard.SelectExisting.ProceedQr": { + readonly def: "Scan the QR code displayed on an active device using this device's camera."; + readonly zh: "使用本设备摄像头扫描活动设备上显示的二维码"; + }; + readonly "Ui.SetupWizard.SelectExisting.ProceedSetupUri": { + readonly def: "Proceed with Setup URI"; + readonly zh: "使用 Setup URI 继续"; + }; + readonly "Ui.SetupWizard.SelectExisting.QrOption": { + readonly def: "Scan a QR Code (Recommended for mobile)"; + readonly zh: "扫描二维码(移动端推荐)"; + }; + readonly "Ui.SetupWizard.SelectExisting.QrOptionDesc": { + readonly def: "Scan the QR code displayed on an active device using this device's camera."; + readonly zh: "使用本设备摄像头扫描活动设备上显示的二维码。"; + }; + readonly "Ui.SetupWizard.SelectExisting.Question": { + readonly def: "Please select a method to import the settings from another device."; + readonly zh: "请选择一种从其他设备导入设置的方法。"; + }; + readonly "Ui.SetupWizard.SelectExisting.SetupUriOption": { + readonly def: "Use a Setup URI (Recommended)"; + readonly zh: "使用 Setup URI(推荐)"; + }; + readonly "Ui.SetupWizard.SelectExisting.SetupUriOptionDesc": { + readonly def: "Paste the Setup URI generated from one of your active devices."; + readonly zh: "粘贴从某台已启用设备生成的 Setup URI。"; + }; + readonly "Ui.SetupWizard.SelectExisting.Title": { + readonly def: "Device Setup Method"; + readonly zh: "设备设置方式"; + }; + readonly "Ui.SetupWizard.SelectNew.Guidance": { + readonly def: "We will now proceed with the server configuration."; + readonly zh: "接下来将继续配置服务器连接信息。"; + }; + readonly "Ui.SetupWizard.SelectNew.ManualOption": { + readonly def: "Enter the server information manually"; + readonly zh: "手动输入服务器信息"; + }; + readonly "Ui.SetupWizard.SelectNew.ManualOptionDesc": { + readonly def: "This is an advanced option for users who do not have a Setup URI or who want to configure detailed settings."; + readonly zh: "如果你没有 Setup URI,或希望自行配置更详细的参数,可选择此高级选项。"; + }; + readonly "Ui.SetupWizard.SelectNew.ProceedManual": { + readonly def: "I know my server details, let me enter them"; + readonly zh: "我知道服务器信息,让我手动输入"; + }; + readonly "Ui.SetupWizard.SelectNew.ProceedSetupUri": { + readonly def: "Proceed with Setup URI"; + readonly zh: "使用 Setup URI 继续"; + }; + readonly "Ui.SetupWizard.SelectNew.Question": { + readonly def: "How would you like to configure the connection to your server?"; + readonly zh: "你希望如何配置服务器连接?"; + }; + readonly "Ui.SetupWizard.SelectNew.SetupUriOption": { + readonly def: "Use a Setup URI (Recommended)"; + readonly zh: "使用 Setup URI(推荐)"; + }; + readonly "Ui.SetupWizard.SelectNew.SetupUriOptionDesc": { + readonly def: "A Setup URI is a single string containing your server address and authentication details. If one was generated by your server installation script, it provides a simple and secure configuration method."; + readonly zh: "Setup URI 是一段包含服务器地址和认证信息的文本。如果你的服务器安装脚本已经生成了它,这是最简单且安全的配置方式。"; + }; + readonly "Ui.SetupWizard.SelectNew.Title": { + readonly def: "Connection Method"; + readonly zh: "连接方式"; + }; + readonly "Ui.SetupWizard.SetupRemote.BucketOption": { + readonly def: "S3/MinIO/R2 Object Storage"; + readonly zh: "S3/MinIO/R2 对象存储"; + }; + readonly "Ui.SetupWizard.SetupRemote.BucketOptionDesc": { + readonly def: "Synchronisation using journal files. You must already have an S3/MinIO/R2 compatible object storage service set up."; + readonly zh: "使用日志文件进行同步。你需要先准备好兼容 S3/MinIO/R2 的对象存储服务。"; + }; + readonly "Ui.SetupWizard.SetupRemote.CouchDbOptionDesc": { + readonly def: "This is the most suitable synchronisation method for the current design. All features are available. You must already have a CouchDB instance set up."; + readonly zh: "这是当前设计下最适合的同步方式,所有功能都可用。你需要先准备好 CouchDB 实例。"; + }; + readonly "Ui.SetupWizard.SetupRemote.Guidance": { + readonly def: "Please select the type of server you are connecting to."; + readonly zh: "请选择你要连接的服务器类型。"; + }; + readonly "Ui.SetupWizard.SetupRemote.P2POption": { + readonly def: "Peer-to-Peer only"; + readonly zh: "仅点对点"; + }; + readonly "Ui.SetupWizard.SetupRemote.P2POptionDesc": { + readonly def: "This enables direct synchronisation between devices. No server is required, but both devices must be online at the same time and some features may be limited. Internet connectivity is required only for signalling, not for data transfer."; + readonly zh: "启用设备之间的直接同步。无需服务器,但两台设备必须同时在线,且部分功能可能受限。互联网连接仅用于信令,不用于传输数据。"; + }; + readonly "Ui.SetupWizard.SetupRemote.ProceedBucket": { + readonly def: "Continue to S3/MinIO/R2 setup"; + readonly zh: "继续配置 S3/MinIO/R2"; + }; + readonly "Ui.SetupWizard.SetupRemote.ProceedCouchDb": { + readonly def: "Continue to CouchDB setup"; + readonly zh: "继续配置 CouchDB"; + }; + readonly "Ui.SetupWizard.SetupRemote.ProceedP2P": { + readonly def: "Continue to Peer-to-Peer only setup"; + readonly zh: "继续配置仅点对点模式"; + }; + readonly "Ui.SetupWizard.SetupRemote.Title": { + readonly def: "Enter Server Information"; + readonly zh: "输入服务器信息"; + }; + readonly "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": { + readonly def: "Unique name between all synchronized devices. To edit this setting, please disable customization sync once."; + readonly es: "Nombre único entre dispositivos sincronizados. Para editarlo, desactive sincronización de personalización"; + readonly fr: "Nom unique parmi tous les appareils synchronisés. Pour modifier ce paramètre, désactivez d'abord la synchronisation de personnalisation."; + readonly he: "שם ייחודי בין כל המכשירים המסונכרנים. כדי לערוך הגדרה זו, אנא נטרל את סנכרון ההתאמה האישית פעם אחת."; + readonly ja: "同期するすべての端末間で重複しない(一意の)名前。この設定を変更する場合、カスタマイズ同期を無効にしてください。"; + readonly ko: "모든 동기화된 기기 간 고유 이름입니다. 이 설정을 편집하려면 사용자 설정 동기화를 한 번 비활성화해 주세요."; + readonly ru: "Уникальное имя между всеми синхронизируемыми устройствами."; + readonly zh: "所有同步设备之间的唯一名称。要编辑此设置,请首先禁用自定义同步"; + }; + readonly "Use a custom passphrase": { + readonly def: "Use a custom passphrase"; + readonly es: "Usar una frase de contraseña personalizada"; + readonly ja: "カスタムパスフレーズを使う"; + readonly ko: "사용자 지정 암호문구 사용"; + readonly ru: "Использовать пользовательскую парольную фразу"; + readonly zh: "使用自定义密码短语"; + }; + readonly "Use a Setup URI (Recommended)": { + readonly def: "Use a Setup URI (Recommended)"; + readonly es: "Usar un URI de configuración (recomendado)"; + readonly ja: "Setup URI を使う(推奨)"; + readonly ko: "설정 URI 사용(권장)"; + readonly ru: "Использовать Setup URI (рекомендуется)"; + readonly zh: "使用 Setup URI(推荐)"; + readonly "zh-tw": "使用 Setup URI(推薦)"; + }; + readonly "Use Custom HTTP Handler": { + readonly def: "Use Custom HTTP Handler"; + readonly es: "Usar manejador HTTP personalizado"; + readonly fr: "Utiliser un gestionnaire HTTP personnalisé"; + readonly he: "השתמש ב-HTTP Handler מותאם אישית"; + readonly ja: "カスタムHTTPハンドラーの利用"; + readonly ko: "커스텀 HTTP 핸들러 사용"; + readonly ru: "Использовать пользовательский HTTP обработчик"; + readonly zh: "使用自定义 HTTP 处理程序"; + }; + readonly "Use dynamic iteration count": { + readonly def: "Use dynamic iteration count"; + readonly es: "Usar conteo de iteraciones dinámico"; + readonly fr: "Utiliser un compteur d'itérations dynamique"; + readonly he: "השתמש בספירת איטרציות דינמית"; + readonly ja: "動的な繰り返し回数"; + readonly ko: "동적 반복 횟수 사용"; + readonly ru: "Использовать динамическое количество итераций"; + readonly zh: "使用动态迭代次数"; + }; + readonly "Use Segmented-splitter": { + readonly def: "Use Segmented-splitter"; + readonly es: "Usar divisor segmentado"; + readonly fr: "Utiliser le découpeur segmenté"; + readonly he: "השתמש ב-Segmented-splitter"; + readonly ja: "セグメント分割を使用"; + readonly ko: "의미 기반 분할 사용"; + readonly ru: "Использовать сегментный разделитель"; + readonly zh: "使用分段分割器"; + }; + readonly "Use splitting-limit-capped chunk splitter": { + readonly def: "Use splitting-limit-capped chunk splitter"; + readonly es: "Usar divisor de chunks con límite"; + readonly fr: "Utiliser le découpeur de fragments plafonné"; + readonly he: "השתמש ב-chunk splitter עם מגבלת פיצול"; + readonly ja: "分割制限付きチャンク分割を使用"; + readonly ko: "분할 제한 상한 청크 분할기 사용"; + readonly ru: "Использовать разделитель чанков с ограничением"; + readonly zh: "使用分割限制上限的块分割器"; + }; + readonly "Use the trash bin": { + readonly def: "Use the trash bin"; + readonly es: "Usar papelera"; + readonly fr: "Utiliser la corbeille"; + readonly he: "השתמש בסל האשפה"; + readonly ja: "ゴミ箱を使用"; + readonly ko: "휴지통 사용"; + readonly ru: "Использовать корзину"; + readonly zh: "使用回收站"; + }; + readonly "Use timeouts instead of heartbeats": { + readonly def: "Use timeouts instead of heartbeats"; + readonly es: "Usar timeouts en lugar de latidos"; + readonly fr: "Utiliser des délais d'attente au lieu de battements"; + readonly he: "השתמש בפסק זמן במקום פעימות לב"; + readonly ja: "ハートビートの代わりにタイムアウトを使用"; + readonly ko: "하트비트 대신 타임아웃 사용"; + readonly ru: "Использовать таймауты вместо пульса"; + readonly zh: "使用超时而不是心跳"; + }; + readonly username: { + readonly def: "username"; + readonly es: "nombre de usuario"; + readonly fr: "nom d'utilisateur"; + readonly he: "שם משתמש"; + readonly ja: "ユーザー名"; + readonly ko: "사용자명"; + readonly ru: "имя пользователя"; + readonly zh: "用户名"; + }; + readonly Username: { + readonly def: "Username"; + readonly es: "Usuario"; + readonly fr: "Nom d'utilisateur"; + readonly he: "שם משתמש"; + readonly ja: "ユーザー名"; + readonly ko: "사용자명"; + readonly ru: "Имя пользователя"; + readonly zh: "用户名"; + }; + readonly "Verbose Log": { + readonly def: "Verbose Log"; + readonly es: "Registro detallado"; + readonly fr: "Journal verbeux"; + readonly he: "יומן מפורט"; + readonly ja: "エラー以外のログ項目"; + readonly ko: "자세한 로그"; + readonly ru: "Подробный лог"; + readonly zh: "详细日志"; + }; + readonly "Verify all": { + readonly def: "Verify all"; + readonly es: "Verificar todo"; + readonly ja: "すべて検証"; + readonly ko: "모두 검증"; + readonly ru: "Проверить всё"; + readonly zh: "全部校验"; + readonly "zh-tw": "全部驗證"; + }; + readonly "Verify and repair all files": { + readonly def: "Verify and repair all files"; + readonly es: "Verificar y reparar todos los archivos"; + readonly ja: "すべてのファイルを検証して修復"; + readonly ko: "모든 파일 검증 및 복구"; + readonly ru: "Проверить и восстановить все файлы"; + readonly zh: "校验并修复所有文件"; + readonly "zh-tw": "驗證並修復所有檔案"; + }; + readonly "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": { + readonly def: "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information."; + readonly es: "¡Advertencia! Impacta rendimiento. Los logs no se sincronizan con nombre predeterminado. Contienen información confidencial"; + readonly fr: "Attention ! Ceci aura un impact important sur les performances. De plus, les journaux ne seront pas synchronisés sous le nom par défaut. Soyez prudent avec les journaux ; ils contiennent souvent des informations confidentielles."; + readonly he: "אזהרה! לכך תהיה השפעה רצינית על הביצועים. בנוסף, היומנים לא יסונכרנו תחת השם ברירת המחדל. אנא היה זהיר עם יומנים; הם לרוב מכילים מידע סודי שלך."; + readonly ja: "警告!これはパフォーマンスに重大な影響を与えます。また、ログはデフォルト名では同期されません。ログには機密情報が含まれることが多いため、注意してください。"; + readonly ko: "경고! 이는 성능에 심각한 영향을 미칩니다. 로그는 기본 이름으로 동기화되지 않습니다. 로그에는 종종 기밀 정보가 포함되어 있으므로 주의해 주세요."; + readonly ru: "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information."; + readonly zh: "警告!这将严重影响性能。并且日志不会以默认名称同步。请小心处理日志;它们通常包含您的敏感信息 "; + }; + readonly "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": { + readonly def: "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name."; + readonly es: "No podemos cambiar el nombre del dispositivo mientras esta función esté habilitada. Deshabilita la función para cambiarlo."; + readonly ja: "この機能が有効な間はデバイス名を変更できません。変更するにはこの機能を無効にしてください。"; + readonly ko: "이 기능이 활성화되어 있는 동안에는 장치 이름을 변경할 수 없습니다. 장치 이름을 변경하려면 이 기능을 비활성화하세요."; + readonly ru: "Невозможно изменить имя устройства, пока эта функция включена. Отключите её, чтобы изменить имя устройства."; + readonly zh: "启用此功能时无法更改设备名称。如需修改设备名称,请先禁用此功能。"; + }; + readonly "We will now guide you through a few questions to simplify the synchronisation setup.": { + readonly def: "We will now guide you through a few questions to simplify the synchronisation setup."; + readonly es: "Ahora le guiaremos con unas pocas preguntas para simplificar la configuración de la sincronización。"; + readonly ja: "これからいくつかの質問に沿って、同期設定を簡単に進めます。"; + readonly ko: "동기화 설정을 더 쉽게 진행할 수 있도록 몇 가지 질문으로 안내해 드리겠습니다。"; + readonly ru: "Сейчас мы зададим несколько вопросов, чтобы упростить настройку синхронизации。"; + readonly zh: "接下来我们会通过几个问题,引导你更轻松地完成同步设置。"; + readonly "zh-tw": "接下來我們會透過幾個問題,引導你更輕鬆地完成同步設定。"; + }; + readonly "We will now proceed with the server configuration.": { + readonly def: "We will now proceed with the server configuration."; + readonly es: "Ahora continuaremos con la configuración del servidor。"; + readonly ja: "次にサーバー設定を進めます。"; + readonly ko: "이제 서버 구성을 진행하겠습니다。"; + readonly ru: "Теперь перейдём к настройке сервера。"; + readonly zh: "接下来将继续进行服务器配置。"; + readonly "zh-tw": "接下來將繼續進行伺服器設定。"; + }; + readonly "Welcome to Self-hosted LiveSync": { + readonly def: "Welcome to Self-hosted LiveSync"; + readonly es: "Bienvenido a Self-hosted LiveSync"; + readonly ja: "Self-hosted LiveSync へようこそ"; + readonly ko: "Self-hosted LiveSync에 오신 것을 환영합니다"; + readonly ru: "Добро пожаловать в Self-hosted LiveSync"; + readonly zh: "欢迎使用 Self-hosted LiveSync"; + readonly "zh-tw": "歡迎使用 Self-hosted LiveSync"; + }; + readonly "When you save a file in the editor, start a sync automatically": { + readonly def: "When you save a file in the editor, start a sync automatically"; + readonly es: "Iniciar sincronización automática al guardar en editor"; + readonly fr: "À l'enregistrement d'un fichier dans l'éditeur, démarrer automatiquement une synchronisation"; + readonly he: "כאשר אתה שומר קובץ בעורך, התחל סנכרון אוטומטית"; + readonly ja: "エディタでファイルを保存すると、自動的に同期を開始します"; + readonly ko: "편집기에서 파일을 저장할 때 자동으로 동기화를 시작합니다"; + readonly ru: "Когда вы сохраняете файл в редакторе, автоматически запускать синхронизацию"; + readonly zh: "当您在编辑器中保存文件时,自动开始同步"; + }; + readonly "Write credentials in the file": { + readonly def: "Write credentials in the file"; + readonly es: "Escribir credenciales en archivo"; + readonly fr: "Écrire les identifiants dans le fichier"; + readonly he: "כתוב פרטי גישה בקובץ"; + readonly ja: "認証情報のファイル内保存"; + readonly ko: "파일에 자격 증명 저장"; + readonly ru: "Записывать учётные данные в файл"; + readonly zh: "将凭据写入文件"; + }; + readonly "Write logs into the file": { + readonly def: "Write logs into the file"; + readonly es: "Escribir logs en archivo"; + readonly fr: "Écrire les journaux dans le fichier"; + readonly he: "כתוב יומנים לקובץ"; + readonly ja: "ファイルにログを記録"; + readonly ko: "파일에 로그 기록"; + readonly ru: "Записывать логи в файл"; + readonly zh: "将日志写入文件"; + }; + readonly "xxhash32 (Fast but less collision resistance)": { + readonly def: "xxhash32 (Fast but less collision resistance)"; + readonly es: "xxhash32 (rápido, pero con menor resistencia a colisiones)"; + readonly ja: "xxhash32 (高速ですが衝突耐性は低め)"; + readonly ko: "xxhash32 (빠르지만 충돌 저항성은 낮음)"; + readonly ru: "xxhash32 (быстрый, но с меньшей устойчивостью к коллизиям)"; + readonly zh: "xxhash32(速度快,但抗碰撞能力较弱)"; + readonly "zh-tw": "xxhash32(速度快,但抗碰撞能力較弱)"; + }; + readonly "xxhash64 (Fastest)": { + readonly def: "xxhash64 (Fastest)"; + readonly es: "xxhash64 (el más rápido)"; + readonly ja: "xxhash64 (最速)"; + readonly ko: "xxhash64 (가장 빠름)"; + readonly ru: "xxhash64 (самый быстрый)"; + readonly zh: "xxhash64(最快)"; + readonly "zh-tw": "xxhash64(最快)"; + }; + readonly "Yes, I want to add this device to my existing synchronisation": { + readonly def: "Yes, I want to add this device to my existing synchronisation"; + readonly es: "Sí, quiero añadir este dispositivo a mi sincronización existente"; + readonly ja: "はい、この端末を既存の同期に追加します"; + readonly ko: "예, 이 장치를 기존 동기화에 추가하겠습니다"; + readonly ru: "Да, я хочу добавить это устройство к существующей синхронизации"; + readonly zh: "是的,我要把这台设备加入现有同步"; + readonly "zh-tw": "是的,我要把這台裝置加入既有同步"; + }; + readonly "Yes, I want to set up a new synchronisation": { + readonly def: "Yes, I want to set up a new synchronisation"; + readonly es: "Sí, quiero configurar una nueva sincronización"; + readonly ja: "はい、新しい同期を設定します"; + readonly ko: "예, 새 동기화를 설정하겠습니다"; + readonly ru: "Да, я хочу настроить новую синхронизацию"; + readonly zh: "是的,我要配置新的同步"; + readonly "zh-tw": "是的,我要設定新的同步"; + }; + readonly "You are adding this device to an existing synchronisation setup.": { + readonly def: "You are adding this device to an existing synchronisation setup."; + readonly es: "Está añadiendo este dispositivo a una configuración de sincronización existente。"; + readonly ja: "この端末を既存の同期構成に追加しようとしています。"; + readonly ko: "이 장치를 기존 동기화 구성에 추가하려고 합니다。"; + readonly ru: "Вы добавляете это устройство к существующей настройке синхронизации。"; + readonly zh: "你正在将此设备加入到现有同步配置中。"; + readonly "zh-tw": "你正在將此裝置加入既有同步設定中。"; + }; + readonly "Compute revisions for chunks (Previous behaviour)": { + readonly es: "Calcular revisiones para chunks (comportamiento anterior)"; + }; + readonly "Setup.> [!INFO]- The connected devices have been detected as follows:\n${devices}": { + readonly es: "> [!INFO]- Se detectaron los siguientes dispositivos conectados:\n${devices}"; + }; + readonly "Setup.All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": { + readonly es: "Todos los dispositivos tienen el mismo valor de progreso (${progress}). Parece que tus dispositivos están sincronizados y se puede continuar con la recolección de basura."; + }; + readonly "Setup.Cancel Garbage Collection": { + readonly es: "Cancelar la recolección de basura"; + }; + readonly "Setup.Compaction in progress on remote database...": { + readonly es: "La compactación está en curso en la base de datos remota..."; + }; + readonly "Setup.Compaction on remote database completed successfully.": { + readonly es: "La compactación en la base de datos remota se completó correctamente."; + }; + readonly "Setup.Compaction on remote database failed.": { + readonly es: "La compactación en la base de datos remota falló."; + }; + readonly "Setup.Compaction on remote database timed out.": { + readonly es: "La compactación en la base de datos remota agotó el tiempo de espera."; + }; + readonly "Setup.Device": { + readonly es: "Dispositivo"; + }; + readonly "Setup.Failed to connect to remote for compaction.": { + readonly es: "No se pudo conectar a la base de datos remota para la compactación."; + }; + readonly "Setup.Failed to connect to remote for compaction. ${reason}": { + readonly es: "No se pudo conectar a la base de datos remota para la compactación. ${reason}"; + }; + readonly "Setup.Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": { + readonly es: "No se pudo iniciar la replicación de una sola vez antes de la recolección de basura. La recolección de basura se canceló."; + }; + readonly "Setup.Failed to start replication after Garbage Collection.": { + readonly es: "No se pudo iniciar la replicación después de la recolección de basura."; + }; + readonly "Setup.Garbage Collection cancelled by user.": { + readonly es: "El usuario canceló la recolección de basura."; + }; + readonly "Setup.Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": { + readonly es: "Recolección de basura completada. Chunks eliminados: ${deletedChunks} / ${totalChunks}. Tiempo empleado: ${seconds} segundos."; + }; + readonly "Setup.Garbage Collection Confirmation": { + readonly es: "Confirmación de recolección de basura"; + }; + readonly "Setup.Garbage Collection: Found ${unusedChunks} unused chunks to delete.": { + readonly es: "Recolección de basura: se encontraron ${unusedChunks} chunks no usados para eliminar."; + }; + readonly "Setup.Garbage Collection: Scanned ${scanned} / ~${docCount}": { + readonly es: "Recolección de basura: escaneados ${scanned} / ~${docCount}"; + }; + readonly "Setup.Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": { + readonly es: "Recolección de basura: escaneo completado. Chunks totales: ${totalChunks}, chunks usados: ${usedChunks}"; + }; + readonly "Setup.Ignore and Proceed": { + readonly es: "Ignorar y continuar"; + }; + readonly "Setup.No connected device information found. Cancelling Garbage Collection.": { + readonly es: "No se encontró información de dispositivos conectados. Cancelando la recolección de basura."; + }; + readonly "Setup.Node ID": { + readonly es: "ID del nodo"; + }; + readonly "Setup.Node Information Missing": { + readonly es: "Falta información del nodo"; + }; + readonly "Setup.Obsidian version": { + readonly es: "Versión de Obsidian"; + }; + readonly "Setup.optionNoSetupUri": { + readonly es: "No, no tengo"; + }; + readonly "Setup.optionRemindNextLaunch": { + readonly es: "Recordármelo en el próximo inicio"; + }; + readonly "Setup.optionSetupWizard": { + readonly es: "Llévame al asistente de configuración"; + }; + readonly "Setup.optionYesFetchAgain": { + readonly es: "Sí, obtener nuevamente"; + }; + readonly "Setup.Please disable 'Read chunks online' in settings to use Garbage Collection.": { + readonly es: "Desactiva \"Read chunks online\" en los ajustes para usar la recolección de basura."; + }; + readonly "Setup.Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": { + readonly es: "Activa \"Compute revisions for chunks\" en los ajustes para usar la recolección de basura."; + }; + readonly "Setup.Please select 'Cancel' explicitly to cancel this operation.": { + readonly es: "Selecciona explícitamente \"Cancelar\" para cancelar esta operación."; + }; + readonly "Setup.Plug-in version": { + readonly es: "Versión del complemento"; + }; + readonly "Setup.Proceed Garbage Collection": { + readonly es: "Continuar con la recolección de basura"; + }; + readonly "Setup.Proceeding with Garbage Collection, ignoring missing nodes.": { + readonly es: "Continuando con la recolección de basura e ignorando los nodos faltantes."; + }; + readonly "Setup.Proceeding with Garbage Collection.": { + readonly es: "Continuando con la recolección de basura."; + }; + readonly "Setup.Progress": { + readonly es: "Progreso"; + }; + readonly "Setup.Setup URI dialog cancelled.": { + readonly es: "Se canceló el diálogo de Setup URI."; + }; + readonly "Setup.Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": { + readonly es: "Algunos dispositivos tienen valores de progreso diferentes (máx.: ${maxProgress}, mín.: ${minProgress}).\nEsto puede indicar que algunos dispositivos no han completado la sincronización, lo que podría causar conflictos. Se recomienda encarecidamente confirmar que todos los dispositivos estén sincronizados antes de continuar."; + }; + readonly "Setup.The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": { + readonly es: "Los siguientes nodos aceptados no tienen información del nodo:\n- ${missingNodes}\n\nEsto indica que no se han conectado desde hace algún tiempo o que se han quedado en una versión anterior.\nSi es posible, es preferible actualizar todos los dispositivos. Si tienes dispositivos que ya no se usan, puedes borrar todos los nodos aceptados bloqueando el remoto una vez."; + }; + readonly "Setup.titleCaseSensitivity": { + readonly es: "Sensibilidad a mayúsculas"; + }; + readonly "Setup.titleRecommendSetupUri": { + readonly es: "Recomendación de uso de URI de configuración"; + }; + readonly "Setup.titleWelcome": { + readonly es: "Bienvenido a Self-hosted LiveSync"; + }; + readonly "(Not recommended) If set, credentials will be stored in the file": { + readonly ru: "(Не рекомендуется) Если установлено, учётные данные будут сохранены в файле"; + }; + readonly "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding.": { + readonly ru: "До v0.17.16 мы использовали старый адаптер для локальной базы данных. Теперь предпочтителен новый адаптер. Однако требуется перестроение локальной базы данных."; + }; + readonly descConnectSetupURI: { + readonly ru: "Это рекомендуемый способ настройки Self-hosted LiveSync с помощью Setup URI."; + }; + readonly descCopySetupURI: { + readonly ru: "Идеально для настройки нового устройства!"; + }; + readonly descEnableLiveSync: { + readonly ru: "Включайте это только после настройки одного из двух вариантов выше."; + }; + readonly descFetchConfigFromRemote: { + readonly ru: "Загрузить необходимые настройки с уже настроенного удалённого сервера."; + }; + readonly descManualSetup: { + readonly ru: "Не рекомендуется, но полезно, если у вас нет Setup URI"; + }; + readonly descTestDatabaseConnection: { + readonly ru: "Открыть подключение к базе данных."; + }; + readonly descValidateDatabaseConfig: { + readonly ru: "Проверяет и исправляет потенциальные проблемы с конфигурацией базы данных."; + }; + readonly "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this.": { + readonly ru: "Если включено, будет использоваться эффективная синхронизация настроек для каждого файла."; + }; + readonly "If this is set, changes to local files which are matched by the ignore files will be skipped.": { + readonly ru: "Если установлено, изменения файлов из списка игнорирования будут пропущены."; + }; + readonly "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely.": { + readonly ru: "Если эта опция включена, PouchDB будет держать соединение открытым 60 секунд."; + }; + readonly "Number of batches to process at a time. Defaults to 40. Minimum is 2.": { + readonly ru: "Количество пакетов для обработки за раз. По умолчанию 40. Минимум 2."; + }; + readonly "Save settings to a markdown file.": { + readonly ru: "Сохранить настройки в файл markdown."; + }; + readonly "The maximum duration for which chunks can be incubated within the document.": { + readonly ru: "Максимальная продолжительность инкубации чанков в документе."; + }; + readonly "The maximum number of chunks that can be incubated within the document.": { + readonly ru: "Максимальное количество инкубируемых чанков в документе."; + }; + readonly "The maximum total size of chunks that can be incubated within the document.": { + readonly ru: "Максимальный общий размер инкубируемых чанков в документе."; + }; + readonly "This passphrase will not be copied to another device. It will be set to until you configure it again.": { + readonly ru: "Эта парольная фраза не будет скопирована на другое устройство."; + }; + readonly "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name.": { + readonly ru: "Внимание! Это серьёзно повлияет на производительность."; + }; +}; diff --git a/_types/lib/src/common/messages/de.d.ts b/_types/lib/src/common/messages/de.d.ts new file mode 100644 index 0000000..3aeae64 --- /dev/null +++ b/_types/lib/src/common/messages/de.d.ts @@ -0,0 +1,297 @@ +export declare const PartialMessages: { + readonly de: { + "(Active)": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + Activate: string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + Back: string; + "Back to non-configured": string; + Cancel: string; + "Cancel Garbage Collection": string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync (Beta3)": string; + "Database Adapter": string; + Default: string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "Disables all synchronization and restart.": string; + "Display name": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Encrypting sensitive configuration items": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Hidden Files": string; + "Hide completely": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "Ignore and Proceed": string; + "Ignore patterns": string; + "Import connection": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "More actions": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Pick a file to resolve conflict": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set this device name": string; + "Plug-in version": string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + Progress: string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + Rename: string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restore or reconstruct local database from remote.": string; + "S3/MinIO/R2 Object Storage": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram!": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setup URI dialog cancelled.": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Show full banner": string; + "Show icon only": string; + "Show status icon instead of file warnings banner": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Use a Setup URI (Recommended)": string; + "Verify all": string; + "Verify and repair all files": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/def.d.ts b/_types/lib/src/common/messages/def.d.ts new file mode 100644 index 0000000..4cf38bf --- /dev/null +++ b/_types/lib/src/common/messages/def.d.ts @@ -0,0 +1,1119 @@ +export declare const PartialMessages: { + readonly def: { + "(Active)": string; + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + "Access Key": string; + Activate: string; + "Active Remote Configuration": string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Always prompt merge conflicts": string; + Analyse: string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Cancel: string; + "Cancel Garbage Collection": string; + "Changing this setting requires migrating existing data (a bit time may be taken) and restarting Obsidian. Please make sure to back up your data before proceeding.": string; + Check: string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Compute revisions for chunks": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Copy Report to clipboard": string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database -> Storage": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Developer: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + "Doctor.RULES.E2EE_V02500.REASON": string; + "Document History": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + "File to view History": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "Hide completely": string; + "Highlight diff": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "If you reached the payload size limit when using IBM Cloudant, please decrease batch size and batch limit to a lower value.": string; + "Ignore and Proceed": string; + "Ignore files": string; + "Ignore patterns": string; + "Import connection": string; + "Incubate Chunks in Document": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Initialise journal received history. On the next sync, every item except this device sent will be downloaded again.": string; + "Initialise journal sent history. On the next sync, every item except this device received will be sent again.": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-he": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.mismatchedTweakDetected": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "Local Database Tweak": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + Merge: string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.fix0256.buttons.checkItLater": string; + "moduleMigration.fix0256.buttons.DismissForever": string; + "moduleMigration.fix0256.buttons.fix": string; + "moduleMigration.fix0256.message": string; + "moduleMigration.fix0256.messageUnrecoverable": string; + "moduleMigration.fix0256.title": string; + "moduleMigration.insecureChunkExist.buttons.fetch": string; + "moduleMigration.insecureChunkExist.buttons.later": string; + "moduleMigration.insecureChunkExist.buttons.rebuild": string; + "moduleMigration.insecureChunkExist.laterMessage": string; + "moduleMigration.insecureChunkExist.message": string; + "moduleMigration.insecureChunkExist.title": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "More actions": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.logServerConfigurationCheck": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.serverVersion": string; + "obsidianLiveSyncSettingTab.titleActiveRemoteServer": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + Open: string; + "Open the dialog": string; + Overwrite: string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Path Obfuscation": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + "Per-file-saved customization sync": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Periodic Sync interval": string; + "Pick a file to resolve conflict": string; + "Pick a file to show history": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": string; + "Please set this device name": string; + "Plug-in version": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + "Process small files in the foreground": string; + Progress: string; + "Property Encryption": string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recovery and Repair": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "RedFlag.FetchRemoteConfig.Buttons.Cancel": string; + "RedFlag.FetchRemoteConfig.Buttons.Fetch": string; + "RedFlag.FetchRemoteConfig.Message": string; + "RedFlag.FetchRemoteConfig.Title": string; + "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client.": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + "Remote server type": string; + "Remote Type": string; + Rename: string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset notification threshold and check the remote database usage": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?": string; + "Restore or reconstruct local database from remote.": string; + "Run Doctor": string; + "S3/MinIO/R2 Object Storage": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for Broken files": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram Switches": string; + "Scram!": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup URI dialog cancelled.": string; + "Setup.Apply.Buttons.ApplyAndFetch": string; + "Setup.Apply.Buttons.ApplyAndMerge": string; + "Setup.Apply.Buttons.ApplyAndRebuild": string; + "Setup.Apply.Buttons.Cancel": string; + "Setup.Apply.Buttons.OnlyApply": string; + "Setup.Apply.Message": string; + "Setup.Apply.Title": string; + "Setup.Apply.WarningRebuildRecommended": string; + "Setup.Doctor.Buttons.No": string; + "Setup.Doctor.Buttons.Yes": string; + "Setup.Doctor.Message": string; + "Setup.Doctor.Title": string; + "Setup.FetchRemoteConf.Buttons.Fetch": string; + "Setup.FetchRemoteConf.Buttons.Skip": string; + "Setup.FetchRemoteConf.Message": string; + "Setup.FetchRemoteConf.Title": string; + "Setup.QRCode": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show full banner": string; + "Show history": string; + "Show icon only": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Storage -> Database": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "The Hash algorithm for chunk IDs": string; + "The IndexedDB adapter often offers superior performance in certain scenarios, but it has been found to cause memory leaks when used with LiveSync mode. When using LiveSync mode, please use IDB adapter instead.": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Transfer Tweak": string; + "TweakMismatchResolve.Action.DisableAutoAcceptCompatible": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.EnableAutoAcceptCompatible": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.AutoAcceptCompatibleUndefined": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.mineUpdated": string; + "TweakMismatchResolve.Message.remoteUpdated": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.AutoAcceptCompatible": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Ui.Common.Signal.Caution": string; + "Ui.Common.Signal.Danger": string; + "Ui.Common.Signal.Notice": string; + "Ui.Common.Signal.Warning": string; + "Ui.Settings.Advanced.LocalDatabaseTweak": string; + "Ui.Settings.Advanced.MemoryCache": string; + "Ui.Settings.Advanced.TransferTweak": string; + "Ui.Settings.Common.Analyse": string; + "Ui.Settings.Common.Back": string; + "Ui.Settings.Common.Check": string; + "Ui.Settings.Common.Configure": string; + "Ui.Settings.Common.Continue": string; + "Ui.Settings.Common.Delete": string; + "Ui.Settings.Common.Fetch": string; + "Ui.Settings.Common.Lock": string; + "Ui.Settings.Common.Merge": string; + "Ui.Settings.Common.Open": string; + "Ui.Settings.Common.Overwrite": string; + "Ui.Settings.Common.Perform": string; + "Ui.Settings.Common.ResetAll": string; + "Ui.Settings.Common.ResolveAll": string; + "Ui.Settings.Common.Scan": string; + "Ui.Settings.Common.Send": string; + "Ui.Settings.Common.Use": string; + "Ui.Settings.Common.VerifyAll": string; + "Ui.Settings.CustomizationSync.OpenDesc": string; + "Ui.Settings.CustomizationSync.Panel": string; + "Ui.Settings.CustomizationSync.WarnChangeDeviceName": string; + "Ui.Settings.CustomizationSync.WarnSetDeviceName": string; + "Ui.Settings.Hatch.AnalyseDatabaseUsage": string; + "Ui.Settings.Hatch.AnalyseDatabaseUsageDesc": string; + "Ui.Settings.Hatch.BackToNonConfigured": string; + "Ui.Settings.Hatch.ConvertNonObfuscated": string; + "Ui.Settings.Hatch.ConvertNonObfuscatedDesc": string; + "Ui.Settings.Hatch.CopyIssueReport": string; + "Ui.Settings.Hatch.DatabaseLabel": string; + "Ui.Settings.Hatch.DatabaseToStorage": string; + "Ui.Settings.Hatch.DeleteCustomizationSyncData": string; + "Ui.Settings.Hatch.GeneratedReport": string; + "Ui.Settings.Hatch.Missing": string; + "Ui.Settings.Hatch.ModifiedSize": string; + "Ui.Settings.Hatch.ModifiedSizeActual": string; + "Ui.Settings.Hatch.PrepareIssueReport": string; + "Ui.Settings.Hatch.RecoveryAndRepair": string; + "Ui.Settings.Hatch.RecreateAll": string; + "Ui.Settings.Hatch.RecreateMissingChunks": string; + "Ui.Settings.Hatch.RecreateMissingChunksDesc": string; + "Ui.Settings.Hatch.ResetPanel": string; + "Ui.Settings.Hatch.ResetRemoteUsage": string; + "Ui.Settings.Hatch.ResetRemoteUsageDesc": string; + "Ui.Settings.Hatch.ResolveAllConflictedFiles": string; + "Ui.Settings.Hatch.ResolveAllConflictedFilesDesc": string; + "Ui.Settings.Hatch.RunDoctor": string; + "Ui.Settings.Hatch.ScanBrokenFiles": string; + "Ui.Settings.Hatch.ScramSwitches": string; + "Ui.Settings.Hatch.ShowHistory": string; + "Ui.Settings.Hatch.StorageLabel": string; + "Ui.Settings.Hatch.StorageToDatabase": string; + "Ui.Settings.Hatch.VerifyAndRepairAllFiles": string; + "Ui.Settings.Hatch.VerifyAndRepairAllFilesDesc": string; + "Ui.Settings.Maintenance.Cleanup": string; + "Ui.Settings.Maintenance.CleanupDesc": string; + "Ui.Settings.Maintenance.DeleteLocalDatabase": string; + "Ui.Settings.Maintenance.EmergencyRestart": string; + "Ui.Settings.Maintenance.EmergencyRestartDesc": string; + "Ui.Settings.Maintenance.FreshStartWipe": string; + "Ui.Settings.Maintenance.FreshStartWipeDesc": string; + "Ui.Settings.Maintenance.GarbageCollection": string; + "Ui.Settings.Maintenance.GarbageCollectionAction": string; + "Ui.Settings.Maintenance.GarbageCollectionDesc": string; + "Ui.Settings.Maintenance.LockServer": string; + "Ui.Settings.Maintenance.LockServerDesc": string; + "Ui.Settings.Maintenance.OverwriteRemote": string; + "Ui.Settings.Maintenance.OverwriteRemoteDesc": string; + "Ui.Settings.Maintenance.OverwriteServerData": string; + "Ui.Settings.Maintenance.OverwriteServerDataDesc": string; + "Ui.Settings.Maintenance.PurgeAllJournalCounter": string; + "Ui.Settings.Maintenance.PurgeAllJournalCounterDesc": string; + "Ui.Settings.Maintenance.RebuildingOperations": string; + "Ui.Settings.Maintenance.Resend": string; + "Ui.Settings.Maintenance.ResendDesc": string; + "Ui.Settings.Maintenance.Reset": string; + "Ui.Settings.Maintenance.ResetAllJournalCounter": string; + "Ui.Settings.Maintenance.ResetAllJournalCounterDesc": string; + "Ui.Settings.Maintenance.ResetJournalReceived": string; + "Ui.Settings.Maintenance.ResetJournalReceivedDesc": string; + "Ui.Settings.Maintenance.ResetJournalSent": string; + "Ui.Settings.Maintenance.ResetJournalSentDesc": string; + "Ui.Settings.Maintenance.ResetLocalSyncInfo": string; + "Ui.Settings.Maintenance.ResetLocalSyncInfoDesc": string; + "Ui.Settings.Maintenance.ResetReceived": string; + "Ui.Settings.Maintenance.ResetSentHistory": string; + "Ui.Settings.Maintenance.ResetThisDevice": string; + "Ui.Settings.Maintenance.ScheduleAndRestart": string; + "Ui.Settings.Maintenance.Scram": string; + "Ui.Settings.Maintenance.SendChunks": string; + "Ui.Settings.Maintenance.Syncing": string; + "Ui.Settings.Maintenance.WarningLockedReadyAction": string; + "Ui.Settings.Maintenance.WarningLockedReadyText": string; + "Ui.Settings.Maintenance.WarningLockedResolveAction": string; + "Ui.Settings.Maintenance.WarningLockedResolveText": string; + "Ui.Settings.Maintenance.WriteRedFlagAndRestart": string; + "Ui.Settings.Patches.CompatibilityConflict": string; + "Ui.Settings.Patches.CompatibilityDatabase": string; + "Ui.Settings.Patches.CompatibilityInternalApi": string; + "Ui.Settings.Patches.CompatibilityMetadata": string; + "Ui.Settings.Patches.CompatibilityRemote": string; + "Ui.Settings.Patches.CompatibilityTrouble": string; + "Ui.Settings.Patches.CurrentAdapter": string; + "Ui.Settings.Patches.DatabaseAdapter": string; + "Ui.Settings.Patches.DatabaseAdapterDesc": string; + "Ui.Settings.Patches.EdgeCaseBehaviour": string; + "Ui.Settings.Patches.EdgeCaseDatabase": string; + "Ui.Settings.Patches.EdgeCaseProcessing": string; + "Ui.Settings.Patches.IndexedDbWarning": string; + "Ui.Settings.Patches.MigratingToIdb": string; + "Ui.Settings.Patches.MigratingToIndexedDb": string; + "Ui.Settings.Patches.MigrationIdbCompleted": string; + "Ui.Settings.Patches.MigrationIdbCompletedFollowUp": string; + "Ui.Settings.Patches.MigrationIndexedDbCompleted": string; + "Ui.Settings.Patches.MigrationIndexedDbCompletedFollowUp": string; + "Ui.Settings.Patches.MigrationWarning": string; + "Ui.Settings.Patches.OperationToIdb": string; + "Ui.Settings.Patches.OperationToIndexedDb": string; + "Ui.Settings.Patches.Remediation": string; + "Ui.Settings.Patches.RemediationChanged": string; + "Ui.Settings.Patches.RemediationNoLimit": string; + "Ui.Settings.Patches.RemediationRestarting": string; + "Ui.Settings.Patches.RemediationRestartLater": string; + "Ui.Settings.Patches.RemediationRestartMessage": string; + "Ui.Settings.Patches.RemediationRestartNow": string; + "Ui.Settings.Patches.RemediationSuffixChanged": string; + "Ui.Settings.Patches.RemediationWithValue": string; + "Ui.Settings.Patches.RemoteDatabaseSunset": string; + "Ui.Settings.Patches.SwitchToIDB": string; + "Ui.Settings.Patches.SwitchToIndexedDb": string; + "Ui.Settings.PowerUsers.ConfigurationEncryption": string; + "Ui.Settings.PowerUsers.ConnectionTweak": string; + "Ui.Settings.PowerUsers.ConnectionTweakDesc": string; + "Ui.Settings.PowerUsers.Default": string; + "Ui.Settings.PowerUsers.Developer": string; + "Ui.Settings.PowerUsers.EncryptSensitiveConfig": string; + "Ui.Settings.PowerUsers.PromptPassphraseEveryLaunch": string; + "Ui.Settings.PowerUsers.UseCustomPassphrase": string; + "Ui.Settings.Remote.Activate": string; + "Ui.Settings.Remote.ActiveSuffix": string; + "Ui.Settings.Remote.AddConnection": string; + "Ui.Settings.Remote.AddRemoteDefaultName": string; + "Ui.Settings.Remote.ConfigureAndChangeRemote": string; + "Ui.Settings.Remote.ConfigureE2EE": string; + "Ui.Settings.Remote.ConfigureRemote": string; + "Ui.Settings.Remote.DeleteRemoteConfirm": string; + "Ui.Settings.Remote.DeleteRemoteTitle": string; + "Ui.Settings.Remote.DisplayName": string; + "Ui.Settings.Remote.DuplicateRemote": string; + "Ui.Settings.Remote.DuplicateRemoteSuffix": string; + "Ui.Settings.Remote.E2EEConfiguration": string; + "Ui.Settings.Remote.Export": string; + "Ui.Settings.Remote.FetchRemoteSettings": string; + "Ui.Settings.Remote.ImportConnection": string; + "Ui.Settings.Remote.ImportConnectionPrompt": string; + "Ui.Settings.Remote.ImportedCouchDb": string; + "Ui.Settings.Remote.ImportedRemote": string; + "Ui.Settings.Remote.MoreActions": string; + "Ui.Settings.Remote.PeerToPeerPanel": string; + "Ui.Settings.Remote.RemoteConfigurationPrefix": string; + "Ui.Settings.Remote.RemoteDatabases": string; + "Ui.Settings.Remote.RemoteName": string; + "Ui.Settings.Remote.RemoteNameCouchDb": string; + "Ui.Settings.Remote.RemoteNameP2P": string; + "Ui.Settings.Remote.RemoteNameS3": string; + "Ui.Settings.Remote.Rename": string; + "Ui.Settings.Selector.AddDefaultPatterns": string; + "Ui.Settings.Selector.CrossPlatform": string; + "Ui.Settings.Selector.Default": string; + "Ui.Settings.Selector.HiddenFiles": string; + "Ui.Settings.Selector.IgnorePatterns": string; + "Ui.Settings.Selector.NonSynchronisingFiles": string; + "Ui.Settings.Selector.NonSynchronisingFilesDesc": string; + "Ui.Settings.Selector.NormalFiles": string; + "Ui.Settings.Selector.OverwritePatterns": string; + "Ui.Settings.Selector.OverwritePatternsDesc": string; + "Ui.Settings.Selector.SynchronisingFiles": string; + "Ui.Settings.Selector.SynchronisingFilesDesc": string; + "Ui.Settings.Selector.TargetPatterns": string; + "Ui.Settings.Selector.TargetPatternsDesc": string; + "Ui.Settings.Setup.RerunWizardButton": string; + "Ui.Settings.Setup.RerunWizardDesc": string; + "Ui.Settings.Setup.RerunWizardName": string; + "Ui.Settings.SyncSettings.Fetch": string; + "Ui.Settings.SyncSettings.Merge": string; + "Ui.Settings.SyncSettings.Overwrite": string; + "Ui.SetupWizard.Common.Back": string; + "Ui.SetupWizard.Common.Cancel": string; + "Ui.SetupWizard.Common.ProceedSelectOption": string; + "Ui.SetupWizard.Intro.ExistingOption": string; + "Ui.SetupWizard.Intro.ExistingOptionDesc": string; + "Ui.SetupWizard.Intro.Guidance": string; + "Ui.SetupWizard.Intro.NewOption": string; + "Ui.SetupWizard.Intro.NewOptionDesc": string; + "Ui.SetupWizard.Intro.ProceedExisting": string; + "Ui.SetupWizard.Intro.ProceedNew": string; + "Ui.SetupWizard.Intro.Question": string; + "Ui.SetupWizard.Intro.Title": string; + "Ui.SetupWizard.OutroAskUserMode.CompatibleOption": string; + "Ui.SetupWizard.OutroAskUserMode.CompatibleOptionDesc": string; + "Ui.SetupWizard.OutroAskUserMode.ExistingOption": string; + "Ui.SetupWizard.OutroAskUserMode.ExistingOptionDesc": string; + "Ui.SetupWizard.OutroAskUserMode.Guidance": string; + "Ui.SetupWizard.OutroAskUserMode.NewOption": string; + "Ui.SetupWizard.OutroAskUserMode.NewOptionDesc": string; + "Ui.SetupWizard.OutroAskUserMode.ProceedApplySettings": string; + "Ui.SetupWizard.OutroAskUserMode.ProceedNext": string; + "Ui.SetupWizard.OutroAskUserMode.Question": string; + "Ui.SetupWizard.OutroAskUserMode.Title": string; + "Ui.SetupWizard.OutroNewUser.GuidancePrimary": string; + "Ui.SetupWizard.OutroNewUser.GuidanceWarning": string; + "Ui.SetupWizard.OutroNewUser.Important": string; + "Ui.SetupWizard.OutroNewUser.Proceed": string; + "Ui.SetupWizard.OutroNewUser.Question": string; + "Ui.SetupWizard.OutroNewUser.Title": string; + "Ui.SetupWizard.SelectExisting.Guidance": string; + "Ui.SetupWizard.SelectExisting.ManualOption": string; + "Ui.SetupWizard.SelectExisting.ManualOptionDesc": string; + "Ui.SetupWizard.SelectExisting.ProceedManual": string; + "Ui.SetupWizard.SelectExisting.ProceedQr": string; + "Ui.SetupWizard.SelectExisting.ProceedSetupUri": string; + "Ui.SetupWizard.SelectExisting.QrOption": string; + "Ui.SetupWizard.SelectExisting.QrOptionDesc": string; + "Ui.SetupWizard.SelectExisting.Question": string; + "Ui.SetupWizard.SelectExisting.SetupUriOption": string; + "Ui.SetupWizard.SelectExisting.SetupUriOptionDesc": string; + "Ui.SetupWizard.SelectExisting.Title": string; + "Ui.SetupWizard.SelectNew.Guidance": string; + "Ui.SetupWizard.SelectNew.ManualOption": string; + "Ui.SetupWizard.SelectNew.ManualOptionDesc": string; + "Ui.SetupWizard.SelectNew.ProceedManual": string; + "Ui.SetupWizard.SelectNew.ProceedSetupUri": string; + "Ui.SetupWizard.SelectNew.Question": string; + "Ui.SetupWizard.SelectNew.SetupUriOption": string; + "Ui.SetupWizard.SelectNew.SetupUriOptionDesc": string; + "Ui.SetupWizard.SelectNew.Title": string; + "Ui.SetupWizard.SetupRemote.BucketOption": string; + "Ui.SetupWizard.SetupRemote.BucketOptionDesc": string; + "Ui.SetupWizard.SetupRemote.CouchDbOptionDesc": string; + "Ui.SetupWizard.SetupRemote.Guidance": string; + "Ui.SetupWizard.SetupRemote.P2POption": string; + "Ui.SetupWizard.SetupRemote.P2POptionDesc": string; + "Ui.SetupWizard.SetupRemote.ProceedBucket": string; + "Ui.SetupWizard.SetupRemote.ProceedCouchDb": string; + "Ui.SetupWizard.SetupRemote.ProceedP2P": string; + "Ui.SetupWizard.SetupRemote.Title": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use a custom passphrase": string; + "Use a Setup URI (Recommended)": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Verify all": string; + "Verify and repair all files": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/es.d.ts b/_types/lib/src/common/messages/es.d.ts new file mode 100644 index 0000000..cf6980a --- /dev/null +++ b/_types/lib/src/common/messages/es.d.ts @@ -0,0 +1,689 @@ +export declare const PartialMessages: { + readonly es: { + "(Active)": string; + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + "Access Key": string; + Activate: string; + "Add default patterns": string; + "Add new connection": string; + "Always prompt merge conflicts": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Cancel: string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Compute revisions for chunks (Previous behaviour)": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Developer: string; + "Device name": string; + "Device Setup Method": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection V3 (Beta)": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore files": string; + "Ignore patterns": string; + "Import connection": string; + "Incubate Chunks in Document": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Interval (sec)": string; + "Keep empty folder": string; + "lang-de": string; + "lang-es": string; + "lang-fr": string; + "lang-ja": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "Local Database Tweak": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + Merge: string; + "Minimum delay for batch database updating": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleObsidianMenu.replicate": string; + "More actions": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Network warning style": string; + "New Remote": string; + "No limit configured": string; + "No, please take me back": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + Open: string; + "Open the dialog": string; + Overwrite: string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Path Obfuscation": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + "Per-file-saved customization sync": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Periodic Sync interval": string; + "Pick a file to resolve conflict": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": string; + "Please set this device name": string; + Presets: string; + "Proceed with Setup URI": string; + "Process small files in the foreground": string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + "Remote server type": string; + "Remote Type": string; + Rename: string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restore or reconstruct local database from remote.": string; + "S3/MinIO/R2 Object Storage": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram!": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setup.> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "Setup.All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Setup.Cancel Garbage Collection": string; + "Setup.Compaction in progress on remote database...": string; + "Setup.Compaction on remote database completed successfully.": string; + "Setup.Compaction on remote database failed.": string; + "Setup.Compaction on remote database timed out.": string; + "Setup.Device": string; + "Setup.Failed to connect to remote for compaction.": string; + "Setup.Failed to connect to remote for compaction. ${reason}": string; + "Setup.Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Setup.Failed to start replication after Garbage Collection.": string; + "Setup.Garbage Collection cancelled by user.": string; + "Setup.Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Setup.Garbage Collection Confirmation": string; + "Setup.Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Setup.Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Setup.Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Setup.Ignore and Proceed": string; + "Setup.No connected device information found. Cancelling Garbage Collection.": string; + "Setup.Node ID": string; + "Setup.Node Information Missing": string; + "Setup.Obsidian version": string; + "Setup.optionNoSetupUri": string; + "Setup.optionRemindNextLaunch": string; + "Setup.optionSetupWizard": string; + "Setup.optionYesFetchAgain": string; + "Setup.Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Setup.Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Setup.Please select 'Cancel' explicitly to cancel this operation.": string; + "Setup.Plug-in version": string; + "Setup.Proceed Garbage Collection": string; + "Setup.Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Setup.Proceeding with Garbage Collection.": string; + "Setup.Progress": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.Setup URI dialog cancelled.": string; + "Setup.Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Setup.The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "Setup.titleCaseSensitivity": string; + "Setup.titleRecommendSetupUri": string; + "Setup.titleWelcome": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show full banner": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Transfer Tweak": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use a custom passphrase": string; + "Use a Setup URI (Recommended)": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Verify all": string; + "Verify and repair all files": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/fr.d.ts b/_types/lib/src/common/messages/fr.d.ts new file mode 100644 index 0000000..40871cb --- /dev/null +++ b/_types/lib/src/common/messages/fr.d.ts @@ -0,0 +1,582 @@ +export declare const PartialMessages: { + readonly fr: { + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "Access Key": string; + "Active Remote Configuration": string; + "Always prompt merge conflicts": string; + Analyse: string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Automatically Sync all files when opening Obsidian.": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Check: string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compute revisions for chunks": string; + "Copy Report to clipboard": string; + "Data Compression": string; + "Database Name": string; + "Database suffix": string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + "Delete old metadata of deleted files on start-up": string; + "Device name": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + "Doctor.RULES.E2EE_V02500.REASON": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + Filename: string; + "Forces the file to be synced when opened.": string; + "Handle files as Case-Sensitive": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore files": string; + "Incubate Chunks in Document": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.fix0256.buttons.checkItLater": string; + "moduleMigration.fix0256.buttons.DismissForever": string; + "moduleMigration.fix0256.buttons.fix": string; + "moduleMigration.fix0256.message": string; + "moduleMigration.fix0256.messageUnrecoverable": string; + "moduleMigration.fix0256.title": string; + "moduleMigration.insecureChunkExist.buttons.fetch": string; + "moduleMigration.insecureChunkExist.buttons.later": string; + "moduleMigration.insecureChunkExist.buttons.rebuild": string; + "moduleMigration.insecureChunkExist.laterMessage": string; + "moduleMigration.insecureChunkExist.message": string; + "moduleMigration.insecureChunkExist.title": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.serverVersion": string; + "obsidianLiveSyncSettingTab.titleActiveRemoteServer": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Path Obfuscation": string; + "Per-file-saved customization sync": string; + "Periodic Sync interval": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Process small files in the foreground": string; + "Property Encryption": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "RedFlag.FetchRemoteConfig.Buttons.Cancel": string; + "RedFlag.FetchRemoteConfig.Buttons.Fetch": string; + "RedFlag.FetchRemoteConfig.Message": string; + "RedFlag.FetchRemoteConfig.Title": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + "Remote server type": string; + "Remote Type": string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + "Reset notification threshold and check the remote database usage": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Run Doctor": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup.Apply.Buttons.ApplyAndFetch": string; + "Setup.Apply.Buttons.ApplyAndMerge": string; + "Setup.Apply.Buttons.ApplyAndRebuild": string; + "Setup.Apply.Buttons.Cancel": string; + "Setup.Apply.Buttons.OnlyApply": string; + "Setup.Apply.Message": string; + "Setup.Apply.Title": string; + "Setup.Apply.WarningRebuildRecommended": string; + "Setup.Doctor.Buttons.No": string; + "Setup.Doctor.Buttons.Yes": string; + "Setup.Doctor.Message": string; + "Setup.Doctor.Title": string; + "Setup.FetchRemoteConf.Buttons.Fetch": string; + "Setup.FetchRemoteConf.Buttons.Skip": string; + "Setup.FetchRemoteConf.Message": string; + "Setup.FetchRemoteConf.Title": string; + "Setup.QRCode": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + }; +}; diff --git a/_types/lib/src/common/messages/he.d.ts b/_types/lib/src/common/messages/he.d.ts new file mode 100644 index 0000000..02eac82 --- /dev/null +++ b/_types/lib/src/common/messages/he.d.ts @@ -0,0 +1,583 @@ +export declare const PartialMessages: { + readonly he: { + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "Access Key": string; + "Active Remote Configuration": string; + "Always prompt merge conflicts": string; + Analyse: string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Automatically Sync all files when opening Obsidian.": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Check: string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compute revisions for chunks": string; + "Copy Report to clipboard": string; + "Data Compression": string; + "Database Name": string; + "Database suffix": string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + "Delete old metadata of deleted files on start-up": string; + "Device name": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + "Doctor.RULES.E2EE_V02500.REASON": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + Filename: string; + "Forces the file to be synced when opened.": string; + "Handle files as Case-Sensitive": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore files": string; + "Incubate Chunks in Document": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-he": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.fix0256.buttons.checkItLater": string; + "moduleMigration.fix0256.buttons.DismissForever": string; + "moduleMigration.fix0256.buttons.fix": string; + "moduleMigration.fix0256.message": string; + "moduleMigration.fix0256.messageUnrecoverable": string; + "moduleMigration.fix0256.title": string; + "moduleMigration.insecureChunkExist.buttons.fetch": string; + "moduleMigration.insecureChunkExist.buttons.later": string; + "moduleMigration.insecureChunkExist.buttons.rebuild": string; + "moduleMigration.insecureChunkExist.laterMessage": string; + "moduleMigration.insecureChunkExist.message": string; + "moduleMigration.insecureChunkExist.title": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.serverVersion": string; + "obsidianLiveSyncSettingTab.titleActiveRemoteServer": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Path Obfuscation": string; + "Per-file-saved customization sync": string; + "Periodic Sync interval": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Process small files in the foreground": string; + "Property Encryption": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "RedFlag.FetchRemoteConfig.Buttons.Cancel": string; + "RedFlag.FetchRemoteConfig.Buttons.Fetch": string; + "RedFlag.FetchRemoteConfig.Message": string; + "RedFlag.FetchRemoteConfig.Title": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + "Remote server type": string; + "Remote Type": string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + "Reset notification threshold and check the remote database usage": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Run Doctor": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup.Apply.Buttons.ApplyAndFetch": string; + "Setup.Apply.Buttons.ApplyAndMerge": string; + "Setup.Apply.Buttons.ApplyAndRebuild": string; + "Setup.Apply.Buttons.Cancel": string; + "Setup.Apply.Buttons.OnlyApply": string; + "Setup.Apply.Message": string; + "Setup.Apply.Title": string; + "Setup.Apply.WarningRebuildRecommended": string; + "Setup.Doctor.Buttons.No": string; + "Setup.Doctor.Buttons.Yes": string; + "Setup.Doctor.Message": string; + "Setup.Doctor.Title": string; + "Setup.FetchRemoteConf.Buttons.Fetch": string; + "Setup.FetchRemoteConf.Buttons.Skip": string; + "Setup.FetchRemoteConf.Message": string; + "Setup.FetchRemoteConf.Title": string; + "Setup.QRCode": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + }; +}; diff --git a/_types/lib/src/common/messages/ja.d.ts b/_types/lib/src/common/messages/ja.d.ts new file mode 100644 index 0000000..100fc70 --- /dev/null +++ b/_types/lib/src/common/messages/ja.d.ts @@ -0,0 +1,838 @@ +export declare const PartialMessages: { + readonly ja: { + "(Active)": string; + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + "Access Key": string; + Activate: string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Always prompt merge conflicts": string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Cancel: string; + "Cancel Garbage Collection": string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Compute revisions for chunks": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Copy Report to clipboard": string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Developer: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + "Doctor.RULES.E2EE_V02500.REASON": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore and Proceed": string; + "Ignore files": string; + "Ignore patterns": string; + "Import connection": string; + "Incubate Chunks in Document": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "Local Database Tweak": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + Merge: string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.fix0256.buttons.checkItLater": string; + "moduleMigration.fix0256.buttons.DismissForever": string; + "moduleMigration.fix0256.buttons.fix": string; + "moduleMigration.fix0256.message": string; + "moduleMigration.fix0256.messageUnrecoverable": string; + "moduleMigration.fix0256.title": string; + "moduleMigration.insecureChunkExist.buttons.fetch": string; + "moduleMigration.insecureChunkExist.buttons.later": string; + "moduleMigration.insecureChunkExist.buttons.rebuild": string; + "moduleMigration.insecureChunkExist.laterMessage": string; + "moduleMigration.insecureChunkExist.message": string; + "moduleMigration.insecureChunkExist.title": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "More actions": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.serverVersion": string; + "obsidianLiveSyncSettingTab.titleActiveRemoteServer": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + Open: string; + "Open the dialog": string; + Overwrite: string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Path Obfuscation": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + "Per-file-saved customization sync": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Periodic Sync interval": string; + "Pick a file to resolve conflict": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": string; + "Please set this device name": string; + "Plug-in version": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + "Process small files in the foreground": string; + Progress: string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "RedFlag.FetchRemoteConfig.Buttons.Cancel": string; + "RedFlag.FetchRemoteConfig.Buttons.Fetch": string; + "RedFlag.FetchRemoteConfig.Message": string; + "RedFlag.FetchRemoteConfig.Title": string; + "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client.": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + "Remote server type": string; + "Remote Type": string; + Rename: string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset notification threshold and check the remote database usage": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restore or reconstruct local database from remote.": string; + "Run Doctor": string; + "S3/MinIO/R2 Object Storage": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for Broken files": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram Switches": string; + "Scram!": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup URI dialog cancelled.": string; + "Setup.Apply.Buttons.ApplyAndFetch": string; + "Setup.Apply.Buttons.ApplyAndMerge": string; + "Setup.Apply.Buttons.ApplyAndRebuild": string; + "Setup.Apply.Buttons.Cancel": string; + "Setup.Apply.Buttons.OnlyApply": string; + "Setup.Apply.Message": string; + "Setup.Apply.Title": string; + "Setup.Apply.WarningRebuildRecommended": string; + "Setup.Doctor.Buttons.No": string; + "Setup.Doctor.Buttons.Yes": string; + "Setup.Doctor.Message": string; + "Setup.Doctor.Title": string; + "Setup.FetchRemoteConf.Buttons.Fetch": string; + "Setup.FetchRemoteConf.Buttons.Skip": string; + "Setup.FetchRemoteConf.Message": string; + "Setup.FetchRemoteConf.Title": string; + "Setup.QRCode": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show full banner": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Transfer Tweak": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use a custom passphrase": string; + "Use a Setup URI (Recommended)": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Verify all": string; + "Verify and repair all files": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/ko.d.ts b/_types/lib/src/common/messages/ko.d.ts new file mode 100644 index 0000000..46aaf5a --- /dev/null +++ b/_types/lib/src/common/messages/ko.d.ts @@ -0,0 +1,800 @@ +export declare const PartialMessages: { + readonly ko: { + "(Active)": string; + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + "Access Key": string; + Activate: string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Always prompt merge conflicts": string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Cancel: string; + "Cancel Garbage Collection": string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Compute revisions for chunks": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Copy Report to clipboard": string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Developer: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore and Proceed": string; + "Ignore files": string; + "Ignore patterns": string; + "Import connection": string; + "Incubate Chunks in Document": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "Local Database Tweak": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + Merge: string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "More actions": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + Open: string; + "Open the dialog": string; + Overwrite: string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Path Obfuscation": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + "Per-file-saved customization sync": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Periodic Sync interval": string; + "Pick a file to resolve conflict": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": string; + "Please set this device name": string; + "Plug-in version": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + "Process small files in the foreground": string; + Progress: string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client.": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + "Remote server type": string; + "Remote Type": string; + Rename: string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset notification threshold and check the remote database usage": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restore or reconstruct local database from remote.": string; + "Run Doctor": string; + "S3/MinIO/R2 Object Storage": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for Broken files": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram Switches": string; + "Scram!": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup URI dialog cancelled.": string; + "Setup.QRCode": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show full banner": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Transfer Tweak": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use a custom passphrase": string; + "Use a Setup URI (Recommended)": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Verify all": string; + "Verify and repair all files": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/ru.d.ts b/_types/lib/src/common/messages/ru.d.ts new file mode 100644 index 0000000..0e17cc5 --- /dev/null +++ b/_types/lib/src/common/messages/ru.d.ts @@ -0,0 +1,858 @@ +export declare const PartialMessages: { + readonly ru: { + "(Active)": string; + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + "Access Key": string; + Activate: string; + "Active Remote Configuration": string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Always prompt merge conflicts": string; + Analyse: string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding.": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Cancel: string; + "Cancel Garbage Collection": string; + Check: string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Compute revisions for chunks": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Copy Report to clipboard": string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + descConnectSetupURI: string; + descCopySetupURI: string; + descEnableLiveSync: string; + descFetchConfigFromRemote: string; + descManualSetup: string; + descTestDatabaseConnection: string; + descValidateDatabaseConfig: string; + desktop: string; + Developer: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + "Doctor.RULES.E2EE_V02500.REASON": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this.": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore and Proceed": string; + "Ignore files": string; + "Ignore patterns": string; + "Import connection": string; + "Incubate Chunks in Document": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + "Local Database Tweak": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + Merge: string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.fix0256.buttons.checkItLater": string; + "moduleMigration.fix0256.buttons.DismissForever": string; + "moduleMigration.fix0256.buttons.fix": string; + "moduleMigration.fix0256.message": string; + "moduleMigration.fix0256.messageUnrecoverable": string; + "moduleMigration.fix0256.title": string; + "moduleMigration.insecureChunkExist.buttons.fetch": string; + "moduleMigration.insecureChunkExist.buttons.later": string; + "moduleMigration.insecureChunkExist.buttons.rebuild": string; + "moduleMigration.insecureChunkExist.laterMessage": string; + "moduleMigration.insecureChunkExist.message": string; + "moduleMigration.insecureChunkExist.title": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "More actions": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2.": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.serverVersion": string; + "obsidianLiveSyncSettingTab.titleActiveRemoteServer": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + Open: string; + "Open the dialog": string; + Overwrite: string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Path Obfuscation": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + "Per-file-saved customization sync": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Periodic Sync interval": string; + "Pick a file to resolve conflict": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": string; + "Please set this device name": string; + "Plug-in version": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + "Process small files in the foreground": string; + Progress: string; + "Property Encryption": string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "RedFlag.FetchRemoteConfig.Buttons.Cancel": string; + "RedFlag.FetchRemoteConfig.Buttons.Fetch": string; + "RedFlag.FetchRemoteConfig.Message": string; + "RedFlag.FetchRemoteConfig.Title": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + "Remote server type": string; + "Remote Type": string; + Rename: string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset notification threshold and check the remote database usage": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restore or reconstruct local database from remote.": string; + "Run Doctor": string; + "S3/MinIO/R2 Object Storage": string; + "Save settings to a markdown file.": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram!": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup URI dialog cancelled.": string; + "Setup.Apply.Buttons.ApplyAndFetch": string; + "Setup.Apply.Buttons.ApplyAndMerge": string; + "Setup.Apply.Buttons.ApplyAndRebuild": string; + "Setup.Apply.Buttons.Cancel": string; + "Setup.Apply.Buttons.OnlyApply": string; + "Setup.Apply.Message": string; + "Setup.Apply.Title": string; + "Setup.Apply.WarningRebuildRecommended": string; + "Setup.Doctor.Buttons.No": string; + "Setup.Doctor.Buttons.Yes": string; + "Setup.Doctor.Message": string; + "Setup.Doctor.Title": string; + "Setup.FetchRemoteConf.Buttons.Fetch": string; + "Setup.FetchRemoteConf.Buttons.Skip": string; + "Setup.FetchRemoteConf.Message": string; + "Setup.FetchRemoteConf.Title": string; + "Setup.QRCode": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show full banner": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document.": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This passphrase will not be copied to another device. It will be set to until you configure it again.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Transfer Tweak": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use a custom passphrase": string; + "Use a Setup URI (Recommended)": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Verify all": string; + "Verify and repair all files": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name.": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/zh-tw.d.ts b/_types/lib/src/common/messages/zh-tw.d.ts new file mode 100644 index 0000000..e16d70e --- /dev/null +++ b/_types/lib/src/common/messages/zh-tw.d.ts @@ -0,0 +1,384 @@ +export declare const PartialMessages: { + readonly "zh-tw": { + "(Active)": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + Activate: string; + "Active Remote Configuration": string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Always prompt merge conflicts": string; + Analyse: string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Bucket Name": string; + Cancel: string; + "Cancel Garbage Collection": string; + Check: string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Copy Report to clipboard": string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database -> Storage": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Developer: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Document History": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + "File to view History": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "Hide completely": string; + "Highlight diff": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If you reached the payload size limit when using IBM Cloudant, please decrease batch size and batch limit to a lower value.": string; + "Ignore and Proceed": string; + "Ignore patterns": string; + "Import connection": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Initialise journal received history. On the next sync, every item except this device sent will be downloaded again.": string; + "Initialise journal sent history. On the next sync, every item except this device received will be sent again.": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "Minimum interval for syncing": string; + "More actions": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Pick a file to resolve conflict": string; + "Pick a file to show history": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set this device name": string; + "Plug-in version": string; + "Prepare the 'report' to create an issue": string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + Progress: string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recovery and Repair": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client.": string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + Rename: string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset notification threshold and check the remote database usage": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?": string; + "Restore or reconstruct local database from remote.": string; + "Run Doctor": string; + "S3/MinIO/R2 Object Storage": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan for Broken files": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram Switches": string; + "Scram!": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setup URI dialog cancelled.": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Show full banner": string; + "Show history": string; + "Show icon only": string; + "Show status icon instead of file warnings banner": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Storage -> Database": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "The IndexedDB adapter often offers superior performance in certain scenarios, but it has been found to cause memory leaks when used with LiveSync mode. When using LiveSync mode, please use IDB adapter instead.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "Use a Setup URI (Recommended)": string; + "Verify all": string; + "Verify and repair all files": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/messages/zh.d.ts b/_types/lib/src/common/messages/zh.d.ts new file mode 100644 index 0000000..f824865 --- /dev/null +++ b/_types/lib/src/common/messages/zh.d.ts @@ -0,0 +1,1093 @@ +export declare const PartialMessages: { + readonly zh: { + "(Active)": string; + "(BETA) Always overwrite with a newer file": string; + "(Beta) Use ignore files": string; + "(Days passed, 0 to disable automatic-deletion)": string; + "(ex. Read chunks online) If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.": string; + "(MB) If this is set, changes to local and remote files that are larger than this will be skipped. If the file becomes smaller again, a newer one will be used.": string; + "(Mega chars)": string; + "(Not recommended) If set, credentials will be stored in the file.": string; + "(Obsolete) Use an old adapter for compatibility": string; + "(RegExp) Empty to sync all files. Set filter as a regular expression to limit synchronising files.": string; + "(RegExp) If this is set, any changes to local and remote files that match this will be skipped.": string; + "(Select this if you are already using synchronisation on another computer or smartphone.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "(Select this if you are configuring this device as the first synchronisation device.) This option is suitable if you are new to LiveSync and want to set it up from scratch.": string; + "> [!INFO]- The connected devices have been detected as follows:\n${devices}": string; + "A Setup URI is a single string of text containing your server address and authentication details. Using a URI, if one was generated by your server installation script, provides a simple and secure configuration.": string; + "Access Key": string; + Activate: string; + "Active Remote Configuration": string; + "Add default patterns": string; + "Add new connection": string; + "All devices have the same progress value (${progress}). Your devices seem to be synchronised. And be able to proceed with Garbage Collection.": string; + "Always prompt merge conflicts": string; + Analyse: string; + "Analyse database usage": string; + "Analyse database usage and generate a TSV report for diagnosis yourself. You can paste the generated report with any spreadsheet you like.": string; + "Apply Latest Change if Conflicting": string; + "Apply preset configuration": string; + "Ask a passphrase at every launch": string; + "Automatically Sync all files when opening Obsidian.": string; + Back: string; + "Back to non-configured": string; + "Batch database update": string; + "Batch limit": string; + "Batch size": string; + "Batch size of on-demand fetching": string; + "Before v0.17.16, we used an old adapter for the local database. Now the new adapter is preferred. However, it needs local database rebuilding. Please disable this toggle when you have enough time. If leave it enabled, also while fetching from the remote database, you will be asked to disable this.": string; + "Bucket Name": string; + Cancel: string; + "Cancel Garbage Collection": string; + Check: string; + "Check and convert non-path-obfuscated files": string; + "Check for documents that have not been converted to path-obfuscated IDs and convert them if necessary.": string; + "cmdConfigSync.showCustomizationSync": string; + "Comma separated `.gitignore, .dockerignore`": string; + "Compaction in progress on remote database...": string; + "Compaction on remote database completed successfully.": string; + "Compaction on remote database failed.": string; + "Compaction on remote database timed out.": string; + "Compare the content of files between on local database and storage. If not matched, you will be asked which one you want to keep.": string; + "Compatibility (Conflict Behaviour)": string; + "Compatibility (Database structure)": string; + "Compatibility (Internal API Usage)": string; + "Compatibility (Metadata)": string; + "Compatibility (Remote Database)": string; + "Compatibility (Trouble addressed)": string; + "Compute revisions for chunks": string; + "Configuration Encryption": string; + Configure: string; + "Configure And Change Remote": string; + "Configure E2EE": string; + "Configure Remote": string; + "Configure the same server information as your other devices again, manually, very advanced users only.": string; + "Connection Method": string; + "Continue to CouchDB setup": string; + "Continue to Peer-to-Peer only setup": string; + "Continue to S3/MinIO/R2 setup": string; + Copy: string; + "Copy Report to clipboard": string; + "CouchDB Connection Tweak": string; + "Cross-platform": string; + "Current adapter: {adapter}": string; + "Customization Sync": string; + "Customization Sync (Beta3)": string; + "Data Compression": string; + "Database Adapter": string; + "Database Name": string; + "Database suffix": string; + Default: string; + "Delay conflict resolution of inactive files": string; + "Delay merge conflict prompt for inactive files.": string; + Delete: string; + "Delete all customization sync data": string; + "Delete all data on the remote server.": string; + "Delete local database to reset or uninstall Self-hosted LiveSync": string; + "Delete old metadata of deleted files on start-up": string; + "Delete Remote Configuration": string; + "Delete remote configuration '{name}'?": string; + desktop: string; + Developer: string; + Device: string; + "Device name": string; + "Device Setup Method": string; + "dialog.yourLanguageAvailable": string; + "dialog.yourLanguageAvailable.btnRevertToDefault": string; + "dialog.yourLanguageAvailable.Title": string; + "Disables all synchronization and restart.": string; + "Disables logging, only shows notifications. Please disable if you report an issue.": string; + "Display Language": string; + "Display name": string; + "Do not check configuration mismatch before replication": string; + "Do not keep metadata of deleted files.": string; + "Do not split chunks in the background": string; + "Do not use internal API": string; + "Doctor.Button.DismissThisVersion": string; + "Doctor.Button.Fix": string; + "Doctor.Button.FixButNoRebuild": string; + "Doctor.Button.No": string; + "Doctor.Button.Skip": string; + "Doctor.Button.Yes": string; + "Doctor.Dialogue.Main": string; + "Doctor.Dialogue.MainFix": string; + "Doctor.Dialogue.Title": string; + "Doctor.Dialogue.TitleAlmostDone": string; + "Doctor.Dialogue.TitleFix": string; + "Doctor.Level.Must": string; + "Doctor.Level.Necessary": string; + "Doctor.Level.Optional": string; + "Doctor.Level.Recommended": string; + "Doctor.Message.NoIssues": string; + "Doctor.Message.RebuildLocalRequired": string; + "Doctor.Message.RebuildRequired": string; + "Doctor.Message.SomeSkipped": string; + "Doctor.RULES.E2EE_V02500.REASON": string; + Duplicate: string; + "Duplicate remote": string; + "E2EE Configuration": string; + "Edge case addressing (Behaviour)": string; + "Edge case addressing (Database)": string; + "Edge case addressing (Processing)": string; + "Emergency restart": string; + "Enable advanced features": string; + "Enable customization sync": string; + "Enable Developers' Debug Tools.": string; + "Enable edge case treatment features": string; + "Enable poweruser features": string; + "Enable this if your Object Storage doesn't support CORS": string; + "Enable this option to automatically apply the most recent change to documents even when it conflicts": string; + "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.": string; + "Encrypting sensitive configuration items": string; + "Encryption phassphrase. If changed, you should overwrite the server's database with the new (encrypted) files.": string; + "End-to-End Encryption": string; + "Endpoint URL": string; + "Enhance chunk size": string; + "Enter Server Information": string; + "Enter the server information manually": string; + Export: string; + "Failed to connect to remote for compaction.": string; + "Failed to connect to remote for compaction. ${reason}": string; + "Failed to start one-shot replication before Garbage Collection. Garbage Collection Cancelled.": string; + "Failed to start replication after Garbage Collection.": string; + Fetch: string; + "Fetch chunks on demand": string; + "Fetch database with previous behaviour": string; + "Fetch remote settings": string; + "File to resolve conflict": string; + Filename: string; + "First, please select the option that best describes your current situation.": string; + "Flag and restart": string; + "Forces the file to be synced when opened.": string; + "Fresh Start Wipe": string; + "Garbage Collection cancelled by user.": string; + "Garbage Collection completed. Deleted chunks: ${deletedChunks} / ${totalChunks}. Time taken: ${seconds} seconds.": string; + "Garbage Collection Confirmation": string; + "Garbage Collection V3 (Beta)": string; + "Garbage Collection: Found ${unusedChunks} unused chunks to delete.": string; + "Garbage Collection: Scanned ${scanned} / ~${docCount}": string; + "Garbage Collection: Scanning completed. Total chunks: ${totalChunks}, Used chunks: ${usedChunks}": string; + "Handle files as Case-Sensitive": string; + "Hidden Files": string; + "Hide completely": string; + "How to display network errors when the sync server is unreachable.": string; + "How would you like to configure the connection to your server?": string; + "I am adding a device to an existing synchronisation setup": string; + "I am setting this up for the first time": string; + "I know my server details, let me enter them": string; + "If disabled(toggled), chunks will be split on the UI thread (Previous behaviour).": string; + "If enabled per-filed efficient customization sync will be used. We need a small migration when enabling this. And all devices should be updated to v0.23.18. Once we enabled this, we lost a compatibility with old versions.": string; + "If enabled, chunks will be split into no more than 100 items. However, dedupe is slightly weaker.": string; + "If enabled, newly created chunks are temporarily kept within the document, and graduated to become independent chunks once stabilised.": string; + "If enabled, the \u26D4 icon will be shown inside the status instead of the file warnings banner. No details will be shown.": string; + "If enabled, the file under 1kb will be processed in the UI thread.": string; + "If enabled, the notification of hidden files change will be suppressed.": string; + "If this enabled, all chunks will be stored with the revision made from its content. (Previous behaviour)": string; + "If this enabled, All files are handled as case-Sensitive (Previous behaviour).": string; + "If this enabled, chunks will be split into semantically meaningful segments. Not all platforms support this feature.": string; + "If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.": string; + "If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.": string; + "Ignore and Proceed": string; + "Ignore files": string; + "Ignore patterns": string; + "Import connection": string; + "Incubate Chunks in Document": string; + "Initialise all journal history, On the next sync, every item will be received and sent.": string; + "Interval (sec)": string; + "K.exp": string; + "K.long_p2p_sync": string; + "K.P2P": string; + "K.Peer": string; + "K.ScanCustomization": string; + "K.short_p2p_sync": string; + "K.title_p2p_sync": string; + "Keep empty folder": string; + lang_def: string; + "lang-de": string; + "lang-def": string; + "lang-es": string; + "lang-fr": string; + "lang-ja": string; + "lang-ko": string; + "lang-ru": string; + "lang-zh": string; + "lang-zh-tw": string; + Later: string; + "Limit: {datetime} ({timestamp})": string; + "LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.": string; + "liveSyncReplicator.beforeLiveSync": string; + "liveSyncReplicator.cantReplicateLowerValue": string; + "liveSyncReplicator.checkingLastSyncPoint": string; + "liveSyncReplicator.couldNotConnectTo": string; + "liveSyncReplicator.couldNotConnectToRemoteDb": string; + "liveSyncReplicator.couldNotConnectToServer": string; + "liveSyncReplicator.couldNotConnectToURI": string; + "liveSyncReplicator.couldNotMarkResolveRemoteDb": string; + "liveSyncReplicator.liveSyncBegin": string; + "liveSyncReplicator.lockRemoteDb": string; + "liveSyncReplicator.markDeviceResolved": string; + "liveSyncReplicator.oneShotSyncBegin": string; + "liveSyncReplicator.remoteDbCorrupted": string; + "liveSyncReplicator.remoteDbCreatedOrConnected": string; + "liveSyncReplicator.remoteDbDestroyed": string; + "liveSyncReplicator.remoteDbDestroyError": string; + "liveSyncReplicator.remoteDbMarkedResolved": string; + "liveSyncReplicator.replicationClosed": string; + "liveSyncReplicator.replicationInProgress": string; + "liveSyncReplicator.retryLowerBatchSize": string; + "liveSyncReplicator.unlockRemoteDb": string; + "liveSyncSetting.errorNoSuchSettingItem": string; + "liveSyncSetting.originalValue": string; + "liveSyncSetting.valueShouldBeInRange": string; + "liveSyncSettings.btnApply": string; + Lock: string; + "Lock Server": string; + "Lock the remote server to prevent synchronization with other devices.": string; + "logPane.autoScroll": string; + "logPane.logWindowOpened": string; + "logPane.pause": string; + "logPane.title": string; + "logPane.wrap": string; + "Maximum delay for batch database updating": string; + "Maximum file size": string; + "Maximum Incubating Chunk Size": string; + "Maximum Incubating Chunks": string; + "Maximum Incubation Period": string; + "MB (0 to disable).": string; + "Memory cache size (by total characters)": string; + "Memory cache size (by total items)": string; + Merge: string; + "Minimum delay for batch database updating": string; + "Minimum interval for syncing": string; + "moduleCheckRemoteSize.logCheckingStorageSizes": string; + "moduleCheckRemoteSize.logCurrentStorageSize": string; + "moduleCheckRemoteSize.logExceededWarning": string; + "moduleCheckRemoteSize.logThresholdEnlarged": string; + "moduleCheckRemoteSize.msgConfirmRebuild": string; + "moduleCheckRemoteSize.msgDatabaseGrowing": string; + "moduleCheckRemoteSize.msgSetDBCapacity": string; + "moduleCheckRemoteSize.option2GB": string; + "moduleCheckRemoteSize.option800MB": string; + "moduleCheckRemoteSize.optionAskMeLater": string; + "moduleCheckRemoteSize.optionDismiss": string; + "moduleCheckRemoteSize.optionIncreaseLimit": string; + "moduleCheckRemoteSize.optionNoWarn": string; + "moduleCheckRemoteSize.optionRebuildAll": string; + "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string; + "moduleCheckRemoteSize.titleDatabaseSizeNotify": string; + "moduleInputUIObsidian.defaultTitleConfirmation": string; + "moduleInputUIObsidian.defaultTitleSelect": string; + "moduleInputUIObsidian.optionNo": string; + "moduleInputUIObsidian.optionYes": string; + "moduleLiveSyncMain.logAdditionalSafetyScan": string; + "moduleLiveSyncMain.logLoadingPlugin": string; + "moduleLiveSyncMain.logPluginInitCancelled": string; + "moduleLiveSyncMain.logPluginVersion": string; + "moduleLiveSyncMain.logReadChangelog": string; + "moduleLiveSyncMain.logSafetyScanCompleted": string; + "moduleLiveSyncMain.logSafetyScanFailed": string; + "moduleLiveSyncMain.logUnloadingPlugin": string; + "moduleLiveSyncMain.logVersionUpdate": string; + "moduleLiveSyncMain.msgScramEnabled": string; + "moduleLiveSyncMain.optionKeepLiveSyncDisabled": string; + "moduleLiveSyncMain.optionResumeAndRestart": string; + "moduleLiveSyncMain.titleScramEnabled": string; + "moduleLocalDatabase.logWaitingForReady": string; + "moduleLog.showLog": string; + "moduleMigration.docUri": string; + "moduleMigration.fix0256.buttons.checkItLater": string; + "moduleMigration.fix0256.buttons.DismissForever": string; + "moduleMigration.fix0256.buttons.fix": string; + "moduleMigration.fix0256.message": string; + "moduleMigration.fix0256.messageUnrecoverable": string; + "moduleMigration.fix0256.title": string; + "moduleMigration.insecureChunkExist.buttons.fetch": string; + "moduleMigration.insecureChunkExist.buttons.later": string; + "moduleMigration.insecureChunkExist.buttons.rebuild": string; + "moduleMigration.insecureChunkExist.laterMessage": string; + "moduleMigration.insecureChunkExist.message": string; + "moduleMigration.insecureChunkExist.title": string; + "moduleMigration.logBulkSendCorrupted": string; + "moduleMigration.logFetchRemoteTweakFailed": string; + "moduleMigration.logLocalDatabaseNotReady": string; + "moduleMigration.logMigratedSameBehaviour": string; + "moduleMigration.logMigrationFailed": string; + "moduleMigration.logRedflag2CreationFail": string; + "moduleMigration.logRemoteTweakUnavailable": string; + "moduleMigration.logSetupCancelled": string; + "moduleMigration.msgFetchRemoteAgain": string; + "moduleMigration.msgInitialSetup": string; + "moduleMigration.msgRecommendSetupUri": string; + "moduleMigration.msgSinceV02321": string; + "moduleMigration.optionAdjustRemote": string; + "moduleMigration.optionDecideLater": string; + "moduleMigration.optionEnableBoth": string; + "moduleMigration.optionEnableFilenameCaseInsensitive": string; + "moduleMigration.optionEnableFixedRevisionForChunks": string; + "moduleMigration.optionHaveSetupUri": string; + "moduleMigration.optionKeepPreviousBehaviour": string; + "moduleMigration.optionManualSetup": string; + "moduleMigration.optionNoAskAgain": string; + "moduleMigration.optionNoSetupUri": string; + "moduleMigration.optionRemindNextLaunch": string; + "moduleMigration.optionSetupViaP2P": string; + "moduleMigration.optionSetupWizard": string; + "moduleMigration.optionYesFetchAgain": string; + "moduleMigration.titleCaseSensitivity": string; + "moduleMigration.titleRecommendSetupUri": string; + "moduleMigration.titleWelcome": string; + "moduleObsidianMenu.replicate": string; + "More actions": string; + "Move remotely deleted files to the trash, instead of deleting.": string; + "Network warning style": string; + "New Remote": string; + "No connected device information found. Cancelling Garbage Collection.": string; + "No limit configured": string; + "No, please take me back": string; + "Node ID": string; + "Node Information Missing": string; + "Non-Synchronising files": string; + "Normal Files": string; + "Not all messages have been translated. And, please revert to \"Default\" when reporting errors.": string; + "Notify all setting files": string; + "Notify customized": string; + "Notify when other device has newly customized.": string; + "Notify when the estimated remote storage size exceeds on start up": string; + "Number of batches to process at a time. Defaults to 40. Minimum is 2. This along with batch size controls how many docs are kept in memory at a time.": string; + "Number of changes to sync at a time. Defaults to 50. Minimum is 2.": string; + "Obsidian version": string; + "obsidianLiveSyncSettingTab.btnApply": string; + "obsidianLiveSyncSettingTab.btnCheck": string; + "obsidianLiveSyncSettingTab.btnCopy": string; + "obsidianLiveSyncSettingTab.btnDisable": string; + "obsidianLiveSyncSettingTab.btnDiscard": string; + "obsidianLiveSyncSettingTab.btnEnable": string; + "obsidianLiveSyncSettingTab.btnFix": string; + "obsidianLiveSyncSettingTab.btnGotItAndUpdated": string; + "obsidianLiveSyncSettingTab.btnNext": string; + "obsidianLiveSyncSettingTab.btnStart": string; + "obsidianLiveSyncSettingTab.btnTest": string; + "obsidianLiveSyncSettingTab.btnUse": string; + "obsidianLiveSyncSettingTab.buttonFetch": string; + "obsidianLiveSyncSettingTab.buttonNext": string; + "obsidianLiveSyncSettingTab.defaultLanguage": string; + "obsidianLiveSyncSettingTab.descConnectSetupURI": string; + "obsidianLiveSyncSettingTab.descCopySetupURI": string; + "obsidianLiveSyncSettingTab.descEnableLiveSync": string; + "obsidianLiveSyncSettingTab.descFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.descManualSetup": string; + "obsidianLiveSyncSettingTab.descTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.descValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.errAccessForbidden": string; + "obsidianLiveSyncSettingTab.errCannotContinueTest": string; + "obsidianLiveSyncSettingTab.errCorsCredentials": string; + "obsidianLiveSyncSettingTab.errCorsNotAllowingCredentials": string; + "obsidianLiveSyncSettingTab.errCorsOrigins": string; + "obsidianLiveSyncSettingTab.errEnableCors": string; + "obsidianLiveSyncSettingTab.errEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.errMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.errMaxRequestSize": string; + "obsidianLiveSyncSettingTab.errMissingWwwAuth": string; + "obsidianLiveSyncSettingTab.errRequireValidUser": string; + "obsidianLiveSyncSettingTab.errRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.labelDisabled": string; + "obsidianLiveSyncSettingTab.labelEnabled": string; + "obsidianLiveSyncSettingTab.levelAdvanced": string; + "obsidianLiveSyncSettingTab.levelEdgeCase": string; + "obsidianLiveSyncSettingTab.levelPowerUser": string; + "obsidianLiveSyncSettingTab.linkOpenInBrowser": string; + "obsidianLiveSyncSettingTab.linkPageTop": string; + "obsidianLiveSyncSettingTab.linkTipsAndTroubleshooting": string; + "obsidianLiveSyncSettingTab.linkTroubleshooting": string; + "obsidianLiveSyncSettingTab.logCannotUseCloudant": string; + "obsidianLiveSyncSettingTab.logCheckingConfigDone": string; + "obsidianLiveSyncSettingTab.logCheckingConfigFailed": string; + "obsidianLiveSyncSettingTab.logCheckingDbConfig": string; + "obsidianLiveSyncSettingTab.logCheckPassphraseFailed": string; + "obsidianLiveSyncSettingTab.logConfiguredDisabled": string; + "obsidianLiveSyncSettingTab.logConfiguredLiveSync": string; + "obsidianLiveSyncSettingTab.logConfiguredPeriodic": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigFail": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigSet": string; + "obsidianLiveSyncSettingTab.logCouchDbConfigUpdated": string; + "obsidianLiveSyncSettingTab.logDatabaseConnected": string; + "obsidianLiveSyncSettingTab.logEncryptionNoPassphrase": string; + "obsidianLiveSyncSettingTab.logEncryptionNoSupport": string; + "obsidianLiveSyncSettingTab.logErrorOccurred": string; + "obsidianLiveSyncSettingTab.logEstimatedSize": string; + "obsidianLiveSyncSettingTab.logPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.logPassphraseNotCompatible": string; + "obsidianLiveSyncSettingTab.logRebuildNote": string; + "obsidianLiveSyncSettingTab.logSelectAnyPreset": string; + "obsidianLiveSyncSettingTab.msgAreYouSureProceed": string; + "obsidianLiveSyncSettingTab.msgChangesNeedToBeApplied": string; + "obsidianLiveSyncSettingTab.msgConfigCheck": string; + "obsidianLiveSyncSettingTab.msgConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.msgConnectionCheck": string; + "obsidianLiveSyncSettingTab.msgConnectionProxyNote": string; + "obsidianLiveSyncSettingTab.msgCurrentOrigin": string; + "obsidianLiveSyncSettingTab.msgDiscardConfirmation": string; + "obsidianLiveSyncSettingTab.msgDone": string; + "obsidianLiveSyncSettingTab.msgEnableCors": string; + "obsidianLiveSyncSettingTab.msgEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.msgEnableEncryptionRecommendation": string; + "obsidianLiveSyncSettingTab.msgFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.msgGenerateSetupURI": string; + "obsidianLiveSyncSettingTab.msgIfConfigNotPersistent": string; + "obsidianLiveSyncSettingTab.msgInvalidPassphrase": string; + "obsidianLiveSyncSettingTab.msgNewVersionNote": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSInfo": string; + "obsidianLiveSyncSettingTab.msgNonHTTPSWarning": string; + "obsidianLiveSyncSettingTab.msgNotice": string; + "obsidianLiveSyncSettingTab.msgObjectStorageWarning": string; + "obsidianLiveSyncSettingTab.msgOriginCheck": string; + "obsidianLiveSyncSettingTab.msgRebuildRequired": string; + "obsidianLiveSyncSettingTab.msgSelectAndApplyPreset": string; + "obsidianLiveSyncSettingTab.msgSetCorsCredentials": string; + "obsidianLiveSyncSettingTab.msgSetCorsOrigins": string; + "obsidianLiveSyncSettingTab.msgSetMaxDocSize": string; + "obsidianLiveSyncSettingTab.msgSetMaxRequestSize": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUser": string; + "obsidianLiveSyncSettingTab.msgSetRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.msgSettingModified": string; + "obsidianLiveSyncSettingTab.msgSettingsUnchangeableDuringSync": string; + "obsidianLiveSyncSettingTab.msgSetWwwAuth": string; + "obsidianLiveSyncSettingTab.nameApplySettings": string; + "obsidianLiveSyncSettingTab.nameConnectSetupURI": string; + "obsidianLiveSyncSettingTab.nameCopySetupURI": string; + "obsidianLiveSyncSettingTab.nameDisableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameDiscardSettings": string; + "obsidianLiveSyncSettingTab.nameEnableHiddenFileSync": string; + "obsidianLiveSyncSettingTab.nameEnableLiveSync": string; + "obsidianLiveSyncSettingTab.nameHiddenFileSynchronization": string; + "obsidianLiveSyncSettingTab.nameManualSetup": string; + "obsidianLiveSyncSettingTab.nameTestConnection": string; + "obsidianLiveSyncSettingTab.nameTestDatabaseConnection": string; + "obsidianLiveSyncSettingTab.nameValidateDatabaseConfig": string; + "obsidianLiveSyncSettingTab.okAdminPrivileges": string; + "obsidianLiveSyncSettingTab.okCorsCredentials": string; + "obsidianLiveSyncSettingTab.okCorsCredentialsForOrigin": string; + "obsidianLiveSyncSettingTab.okCorsOriginMatched": string; + "obsidianLiveSyncSettingTab.okCorsOrigins": string; + "obsidianLiveSyncSettingTab.okEnableCors": string; + "obsidianLiveSyncSettingTab.okEnableCorsChttpd": string; + "obsidianLiveSyncSettingTab.okMaxDocumentSize": string; + "obsidianLiveSyncSettingTab.okMaxRequestSize": string; + "obsidianLiveSyncSettingTab.okRequireValidUser": string; + "obsidianLiveSyncSettingTab.okRequireValidUserAuth": string; + "obsidianLiveSyncSettingTab.okWwwAuth": string; + "obsidianLiveSyncSettingTab.optionApply": string; + "obsidianLiveSyncSettingTab.optionCancel": string; + "obsidianLiveSyncSettingTab.optionCouchDB": string; + "obsidianLiveSyncSettingTab.optionDisableAllAutomatic": string; + "obsidianLiveSyncSettingTab.optionFetchFromRemote": string; + "obsidianLiveSyncSettingTab.optionHere": string; + "obsidianLiveSyncSettingTab.optionLiveSync": string; + "obsidianLiveSyncSettingTab.optionMinioS3R2": string; + "obsidianLiveSyncSettingTab.optionOkReadEverything": string; + "obsidianLiveSyncSettingTab.optionOnEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicAndEvents": string; + "obsidianLiveSyncSettingTab.optionPeriodicWithBatch": string; + "obsidianLiveSyncSettingTab.optionRebuildBoth": string; + "obsidianLiveSyncSettingTab.optionSaveOnlySettings": string; + "obsidianLiveSyncSettingTab.panelChangeLog": string; + "obsidianLiveSyncSettingTab.panelGeneralSettings": string; + "obsidianLiveSyncSettingTab.panelPrivacyEncryption": string; + "obsidianLiveSyncSettingTab.panelRemoteConfiguration": string; + "obsidianLiveSyncSettingTab.panelSetup": string; + "obsidianLiveSyncSettingTab.serverVersion": string; + "obsidianLiveSyncSettingTab.titleActiveRemoteServer": string; + "obsidianLiveSyncSettingTab.titleAppearance": string; + "obsidianLiveSyncSettingTab.titleConflictResolution": string; + "obsidianLiveSyncSettingTab.titleCongratulations": string; + "obsidianLiveSyncSettingTab.titleCouchDB": string; + "obsidianLiveSyncSettingTab.titleDeletionPropagation": string; + "obsidianLiveSyncSettingTab.titleEncryptionNotEnabled": string; + "obsidianLiveSyncSettingTab.titleEncryptionPassphraseInvalid": string; + "obsidianLiveSyncSettingTab.titleExtraFeatures": string; + "obsidianLiveSyncSettingTab.titleFetchConfig": string; + "obsidianLiveSyncSettingTab.titleFetchConfigFromRemote": string; + "obsidianLiveSyncSettingTab.titleFetchSettings": string; + "obsidianLiveSyncSettingTab.titleHiddenFiles": string; + "obsidianLiveSyncSettingTab.titleLogging": string; + "obsidianLiveSyncSettingTab.titleMinioS3R2": string; + "obsidianLiveSyncSettingTab.titleNotification": string; + "obsidianLiveSyncSettingTab.titleOnlineTips": string; + "obsidianLiveSyncSettingTab.titleQuickSetup": string; + "obsidianLiveSyncSettingTab.titleRebuildRequired": string; + "obsidianLiveSyncSettingTab.titleRemoteConfigCheckFailed": string; + "obsidianLiveSyncSettingTab.titleRemoteServer": string; + "obsidianLiveSyncSettingTab.titleReset": string; + "obsidianLiveSyncSettingTab.titleSetupOtherDevices": string; + "obsidianLiveSyncSettingTab.titleSynchronizationMethod": string; + "obsidianLiveSyncSettingTab.titleSynchronizationPreset": string; + "obsidianLiveSyncSettingTab.titleSyncSettings": string; + "obsidianLiveSyncSettingTab.titleSyncSettingsViaMarkdown": string; + "obsidianLiveSyncSettingTab.titleUpdateThinning": string; + "obsidianLiveSyncSettingTab.warnCorsOriginUnmatched": string; + "obsidianLiveSyncSettingTab.warnNoAdmin": string; + Ok: string; + "Old Algorithm": string; + "Older fallback (Slow, W/O WebAssembly)": string; + Open: string; + "Open the dialog": string; + Overwrite: string; + "Overwrite patterns": string; + "Overwrite remote": string; + "Overwrite remote with local DB and passphrase.": string; + "Overwrite Server Data with This Device's Files": string; + "P2P.AskPassphraseForDecrypt": string; + "P2P.AskPassphraseForShare": string; + "P2P.DisabledButNeed": string; + "P2P.FailedToOpen": string; + "P2P.NoAutoSyncPeers": string; + "P2P.NoKnownPeers": string; + "P2P.Note.description": string; + "P2P.Note.important_note": string; + "P2P.Note.important_note_sub": string; + "P2P.Note.Summary": string; + "P2P.NotEnabled": string; + "P2P.P2PReplication": string; + "P2P.PaneTitle": string; + "P2P.ReplicatorInstanceMissing": string; + "P2P.SeemsOffline": string; + "P2P.SyncAlreadyRunning": string; + "P2P.SyncCompleted": string; + "P2P.SyncStartedWith": string; + "paneMaintenance.markDeviceResolvedAfterBackup": string; + "paneMaintenance.remoteLockedAndDeviceNotAccepted": string; + "paneMaintenance.remoteLockedResolvedDevice": string; + "paneMaintenance.unlockDatabaseReady": string; + Passphrase: string; + "Passphrase of sensitive configuration items": string; + password: string; + Password: string; + "Paste a connection string": string; + "Paste the Setup URI generated from one of your active devices.": string; + "Path Obfuscation": string; + "Patterns to match files for overwriting instead of merging": string; + "Patterns to match files for syncing": string; + "Peer-to-Peer only": string; + "Peer-to-Peer Synchronisation": string; + "Per-file-saved customization sync": string; + Perform: string; + "Perform cleanup": string; + "Perform Garbage Collection": string; + "Perform Garbage Collection to remove unused chunks and reduce database size.": string; + "Periodic Sync interval": string; + "Pick a file to resolve conflict": string; + "Please disable 'Read chunks online' in settings to use Garbage Collection.": string; + "Please enable 'Compute revisions for chunks' in settings to use Garbage Collection.": string; + "Please select 'Cancel' explicitly to cancel this operation.": string; + "Please select a method to import the settings from another device.": string; + "Please select an option to proceed": string; + "Please select the type of server to which you are connecting.": string; + "Please set device name to identify this device. This name should be unique among your devices. While not configured, we cannot enable this feature.": string; + "Please set this device name": string; + "Plug-in version": string; + "Prepare the 'report' to create an issue": string; + Presets: string; + "Proceed Garbage Collection": string; + "Proceed with Setup URI": string; + "Proceeding with Garbage Collection, ignoring missing nodes.": string; + "Proceeding with Garbage Collection.": string; + "Process small files in the foreground": string; + Progress: string; + "Property Encryption": string; + "PureJS fallback (Fast, W/O WebAssembly)": string; + "Purge all download/upload cache.": string; + "Purge all journal counter": string; + "Rebuild local and remote database with local files.": string; + "Rebuilding Operations (Remote Only)": string; + "Recreate all": string; + "Recreate missing chunks for all files": string; + "RedFlag.Fetch.Method.Desc": string; + "RedFlag.Fetch.Method.FetchSafer": string; + "RedFlag.Fetch.Method.FetchSmoother": string; + "RedFlag.Fetch.Method.FetchTraditional": string; + "RedFlag.Fetch.Method.Title": string; + "RedFlag.FetchRemoteConfig.Buttons.Cancel": string; + "RedFlag.FetchRemoteConfig.Buttons.Fetch": string; + "RedFlag.FetchRemoteConfig.Message": string; + "RedFlag.FetchRemoteConfig.Title": string; + "Reduces storage space by discarding all non-latest revisions. This requires the same amount of free space on the remote server and the local client.": string; + "Reducing the frequency with which on-disk changes are reflected into the DB": string; + Region: string; + Remediation: string; + "Remediation Setting Changed": string; + "Remote Database Tweak (In sunset)": string; + "Remote Databases": string; + "Remote name": string; + "Remote server type": string; + "Remote Type": string; + Rename: string; + "Replicator.Dialogue.Locked.Action.Dismiss": string; + "Replicator.Dialogue.Locked.Action.Fetch": string; + "Replicator.Dialogue.Locked.Action.Unlock": string; + "Replicator.Dialogue.Locked.Message": string; + "Replicator.Dialogue.Locked.Message.Fetch": string; + "Replicator.Dialogue.Locked.Message.Unlocked": string; + "Replicator.Dialogue.Locked.Title": string; + "Replicator.Message.Cleaned": string; + "Replicator.Message.InitialiseFatalError": string; + "Replicator.Message.Pending": string; + "Replicator.Message.SomeModuleFailed": string; + "Replicator.Message.VersionUpFlash": string; + "Requires restart of Obsidian": string; + "Requires restart of Obsidian.": string; + "Rerun Onboarding Wizard": string; + "Rerun the onboarding wizard to set up Self-hosted LiveSync again.": string; + "Rerun Wizard": string; + Resend: string; + "Resend all chunks to the remote.": string; + Reset: string; + "Reset all": string; + "Reset all journal counter": string; + "Reset journal received history": string; + "Reset journal sent history": string; + "Reset notification threshold and check the remote database usage": string; + "Reset received": string; + "Reset sent history": string; + "Reset Synchronisation information": string; + "Reset Synchronisation on This Device": string; + "Reset the remote storage size threshold and check the remote storage size again.": string; + "Resolve All": string; + "Resolve all conflicted files": string; + "Resolve All conflicted files by the newer one": string; + "Resolve all conflicted files by the newer one. Caution: This will overwrite the older one, and cannot resurrect the overwritten one.": string; + "Restart Now": string; + "Restore or reconstruct local database from remote.": string; + "Run Doctor": string; + "S3/MinIO/R2 Object Storage": string; + "Save settings to a markdown file. You will be notified when new settings arrive. You can set different files by the platform.": string; + "Saving will be performed forcefully after this number of seconds.": string; + "Scan a QR Code (Recommended for mobile)": string; + "Scan changes on customization sync": string; + "Scan customization automatically": string; + "Scan customization before replicating.": string; + "Scan customization every 1 minute.": string; + "Scan customization periodically": string; + "Scan for Broken files": string; + "Scan for hidden files before replication": string; + "Scan hidden files periodically": string; + "Scan the QR code displayed on an active device using this device's camera.": string; + "Schedule and Restart": string; + "Scram Switches": string; + "Scram!": string; + "Seconds, 0 to disable": string; + "Seconds. Saving to the local database will be delayed until this value after we stop typing or saving.": string; + "Secret Key": string; + "Select the database adapter to use.": string; + Send: string; + "Send chunks": string; + "Server URI": string; + "Setting.GenerateKeyPair.Desc": string; + "Setting.GenerateKeyPair.Title": string; + "Setting.TroubleShooting": string; + "Setting.TroubleShooting.Doctor": string; + "Setting.TroubleShooting.Doctor.Desc": string; + "Setting.TroubleShooting.ScanBrokenFiles": string; + "Setting.TroubleShooting.ScanBrokenFiles.Desc": string; + "SettingTab.Message.AskRebuild": string; + "Setup URI dialog cancelled.": string; + "Setup.Apply.Buttons.ApplyAndFetch": string; + "Setup.Apply.Buttons.ApplyAndMerge": string; + "Setup.Apply.Buttons.ApplyAndRebuild": string; + "Setup.Apply.Buttons.Cancel": string; + "Setup.Apply.Buttons.OnlyApply": string; + "Setup.Apply.Message": string; + "Setup.Apply.Title": string; + "Setup.Apply.WarningRebuildRecommended": string; + "Setup.Doctor.Buttons.No": string; + "Setup.Doctor.Buttons.Yes": string; + "Setup.Doctor.Message": string; + "Setup.Doctor.Title": string; + "Setup.FetchRemoteConf.Buttons.Fetch": string; + "Setup.FetchRemoteConf.Buttons.Skip": string; + "Setup.FetchRemoteConf.Message": string; + "Setup.FetchRemoteConf.Title": string; + "Setup.QRCode": string; + "Setup.RemoteE2EE.AdvancedTitle": string; + "Setup.RemoteE2EE.AlgorithmWarning": string; + "Setup.RemoteE2EE.ButtonCancel": string; + "Setup.RemoteE2EE.ButtonProceed": string; + "Setup.RemoteE2EE.DefaultAlgorithmDesc": string; + "Setup.RemoteE2EE.Guidance": string; + "Setup.RemoteE2EE.LabelEncrypt": string; + "Setup.RemoteE2EE.LabelEncryptionAlgorithm": string; + "Setup.RemoteE2EE.LabelObfuscateProperties": string; + "Setup.RemoteE2EE.MultiDestinationWarning": string; + "Setup.RemoteE2EE.ObfuscatePropertiesDesc": string; + "Setup.RemoteE2EE.PassphraseValidationLine1": string; + "Setup.RemoteE2EE.PassphraseValidationLine2": string; + "Setup.RemoteE2EE.PlaceholderPassphrase": string; + "Setup.RemoteE2EE.StronglyRecommendedLine1": string; + "Setup.RemoteE2EE.StronglyRecommendedLine2": string; + "Setup.RemoteE2EE.StronglyRecommendedTitle": string; + "Setup.RemoteE2EE.Title": string; + "Setup.ScanQRCode.ButtonClose": string; + "Setup.ScanQRCode.Guidance": string; + "Setup.ScanQRCode.Step1": string; + "Setup.ScanQRCode.Step2": string; + "Setup.ScanQRCode.Step3": string; + "Setup.ScanQRCode.Step4": string; + "Setup.ScanQRCode.Title": string; + "Setup.ShowQRCode": string; + "Setup.ShowQRCode.Desc": string; + "Setup.UseSetupURI.ButtonCancel": string; + "Setup.UseSetupURI.ButtonProceed": string; + "Setup.UseSetupURI.ErrorFailedToParse": string; + "Setup.UseSetupURI.ErrorPassphraseRequired": string; + "Setup.UseSetupURI.GuidanceLine1": string; + "Setup.UseSetupURI.GuidanceLine2": string; + "Setup.UseSetupURI.InvalidInfo": string; + "Setup.UseSetupURI.LabelPassphrase": string; + "Setup.UseSetupURI.LabelSetupURI": string; + "Setup.UseSetupURI.PlaceholderPassphrase": string; + "Setup.UseSetupURI.Title": string; + "Setup.UseSetupURI.ValidInfo": string; + "Should we keep folders that don't have any files inside?": string; + "Should we only check for conflicts when a file is opened?": string; + "Should we prompt you about conflicting files when a file is opened?": string; + "Should we prompt you for every single merge, even if we can safely merge automatcially?": string; + "Show full banner": string; + "Show icon only": string; + "Show only notifications": string; + "Show status as icons only": string; + "Show status icon instead of file warnings banner": string; + "Show status inside the editor": string; + "Show status on the status bar": string; + "Show verbose log. Please enable if you report an issue.": string; + "Some devices have differing progress values (max: ${maxProgress}, min: ${minProgress}).\nThis may indicate that some devices have not completed synchronisation, which could lead to conflicts. Strongly recommend confirming that all devices are synchronised before proceeding.": string; + "Starts synchronisation when a file is saved.": string; + "Stop reflecting database changes to storage files.": string; + "Stop watching for file changes.": string; + "Suppress notification of hidden files change": string; + "Suspend database reflecting": string; + "Suspend file watching": string; + "Switch to IDB": string; + "Switch to IndexedDB": string; + "Sync after merging file": string; + "Sync automatically after merging files": string; + "Sync Mode": string; + "Sync on Editor Save": string; + "Sync on File Open": string; + "Sync on Save": string; + "Sync on Startup": string; + "Synchronisation utilising journal files. You must have set up an S3/MinIO/R2 compatible object storage.": string; + "Synchronising files": string; + Syncing: string; + "Target patterns": string; + "Testing only - Resolve file conflicts by syncing newer copies of the file, this can overwrite modified files. Be Warned.": string; + "The delay for consecutive on-demand fetches": string; + "The following accepted nodes are missing its node information:\n- ${missingNodes}\n\nThis indicates that they have not been connected for some time or have been left on an older version.\nIt is preferable to update all devices if possible. If you have any devices that are no longer in use, you can clear all accepted nodes by locking the remote once.": string; + "The Hash algorithm for chunk IDs": string; + "The maximum duration for which chunks can be incubated within the document. Chunks exceeding this period will graduate to independent chunks.": string; + "The maximum number of chunks that can be incubated within the document. Chunks exceeding this number will immediately graduate to independent chunks.": string; + "The maximum total size of chunks that can be incubated within the document. Chunks exceeding this size will immediately graduate to independent chunks.": string; + "The minimum interval for automatic synchronisation on event.": string; + "This feature enables direct synchronisation between devices. No server is required, but both devices must be online at the same time for synchronisation to occur, and some features may be limited. Internet connection is only required to signalling (detecting peers) and not for data transfer.": string; + "This is an advanced option for users who do not have a URI or who wish to configure detailed settings.": string; + "This is the most suitable synchronisation method for the design. All functions are available. You must have set up a CouchDB instance.": string; + "This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.": string; + "This will recreate chunks for all files. If there were missing chunks, this may fix the errors.": string; + "TweakMismatchResolve.Action.Dismiss": string; + "TweakMismatchResolve.Action.UseConfigured": string; + "TweakMismatchResolve.Action.UseMine": string; + "TweakMismatchResolve.Action.UseMineAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseMineWithRebuild": string; + "TweakMismatchResolve.Action.UseRemote": string; + "TweakMismatchResolve.Action.UseRemoteAcceptIncompatible": string; + "TweakMismatchResolve.Action.UseRemoteWithRebuild": string; + "TweakMismatchResolve.Message.Main": string; + "TweakMismatchResolve.Message.MainTweakResolving": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRecommended": string; + "TweakMismatchResolve.Message.UseRemote.WarningRebuildRequired": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRecommended": string; + "TweakMismatchResolve.Message.WarningIncompatibleRebuildRequired": string; + "TweakMismatchResolve.Table": string; + "TweakMismatchResolve.Table.Row": string; + "TweakMismatchResolve.Title": string; + "TweakMismatchResolve.Title.TweakResolving": string; + "TweakMismatchResolve.Title.UseRemoteConfig": string; + "Ui.Common.Signal.Caution": string; + "Ui.Common.Signal.Danger": string; + "Ui.Common.Signal.Notice": string; + "Ui.Common.Signal.Warning": string; + "Ui.Settings.Advanced.LocalDatabaseTweak": string; + "Ui.Settings.Advanced.MemoryCache": string; + "Ui.Settings.Advanced.TransferTweak": string; + "Ui.Settings.Common.Analyse": string; + "Ui.Settings.Common.Back": string; + "Ui.Settings.Common.Check": string; + "Ui.Settings.Common.Configure": string; + "Ui.Settings.Common.Continue": string; + "Ui.Settings.Common.Delete": string; + "Ui.Settings.Common.Fetch": string; + "Ui.Settings.Common.Lock": string; + "Ui.Settings.Common.Merge": string; + "Ui.Settings.Common.Open": string; + "Ui.Settings.Common.Overwrite": string; + "Ui.Settings.Common.Perform": string; + "Ui.Settings.Common.ResetAll": string; + "Ui.Settings.Common.ResolveAll": string; + "Ui.Settings.Common.Scan": string; + "Ui.Settings.Common.Send": string; + "Ui.Settings.Common.Use": string; + "Ui.Settings.Common.VerifyAll": string; + "Ui.Settings.CustomizationSync.OpenDesc": string; + "Ui.Settings.CustomizationSync.Panel": string; + "Ui.Settings.CustomizationSync.WarnChangeDeviceName": string; + "Ui.Settings.CustomizationSync.WarnSetDeviceName": string; + "Ui.Settings.Hatch.AnalyseDatabaseUsage": string; + "Ui.Settings.Hatch.AnalyseDatabaseUsageDesc": string; + "Ui.Settings.Hatch.BackToNonConfigured": string; + "Ui.Settings.Hatch.ConvertNonObfuscated": string; + "Ui.Settings.Hatch.ConvertNonObfuscatedDesc": string; + "Ui.Settings.Hatch.CopyIssueReport": string; + "Ui.Settings.Hatch.DatabaseLabel": string; + "Ui.Settings.Hatch.DatabaseToStorage": string; + "Ui.Settings.Hatch.DeleteCustomizationSyncData": string; + "Ui.Settings.Hatch.GeneratedReport": string; + "Ui.Settings.Hatch.Missing": string; + "Ui.Settings.Hatch.ModifiedSize": string; + "Ui.Settings.Hatch.ModifiedSizeActual": string; + "Ui.Settings.Hatch.PrepareIssueReport": string; + "Ui.Settings.Hatch.RecoveryAndRepair": string; + "Ui.Settings.Hatch.RecreateAll": string; + "Ui.Settings.Hatch.RecreateMissingChunks": string; + "Ui.Settings.Hatch.RecreateMissingChunksDesc": string; + "Ui.Settings.Hatch.ResetPanel": string; + "Ui.Settings.Hatch.ResetRemoteUsage": string; + "Ui.Settings.Hatch.ResetRemoteUsageDesc": string; + "Ui.Settings.Hatch.ResolveAllConflictedFiles": string; + "Ui.Settings.Hatch.ResolveAllConflictedFilesDesc": string; + "Ui.Settings.Hatch.RunDoctor": string; + "Ui.Settings.Hatch.ScanBrokenFiles": string; + "Ui.Settings.Hatch.ScramSwitches": string; + "Ui.Settings.Hatch.ShowHistory": string; + "Ui.Settings.Hatch.StorageLabel": string; + "Ui.Settings.Hatch.StorageToDatabase": string; + "Ui.Settings.Hatch.VerifyAndRepairAllFiles": string; + "Ui.Settings.Hatch.VerifyAndRepairAllFilesDesc": string; + "Ui.Settings.Maintenance.Cleanup": string; + "Ui.Settings.Maintenance.CleanupDesc": string; + "Ui.Settings.Maintenance.DeleteLocalDatabase": string; + "Ui.Settings.Maintenance.EmergencyRestart": string; + "Ui.Settings.Maintenance.EmergencyRestartDesc": string; + "Ui.Settings.Maintenance.FreshStartWipe": string; + "Ui.Settings.Maintenance.FreshStartWipeDesc": string; + "Ui.Settings.Maintenance.GarbageCollection": string; + "Ui.Settings.Maintenance.GarbageCollectionAction": string; + "Ui.Settings.Maintenance.GarbageCollectionDesc": string; + "Ui.Settings.Maintenance.LockServer": string; + "Ui.Settings.Maintenance.LockServerDesc": string; + "Ui.Settings.Maintenance.OverwriteRemote": string; + "Ui.Settings.Maintenance.OverwriteRemoteDesc": string; + "Ui.Settings.Maintenance.OverwriteServerData": string; + "Ui.Settings.Maintenance.OverwriteServerDataDesc": string; + "Ui.Settings.Maintenance.PurgeAllJournalCounter": string; + "Ui.Settings.Maintenance.PurgeAllJournalCounterDesc": string; + "Ui.Settings.Maintenance.RebuildingOperations": string; + "Ui.Settings.Maintenance.Resend": string; + "Ui.Settings.Maintenance.ResendDesc": string; + "Ui.Settings.Maintenance.Reset": string; + "Ui.Settings.Maintenance.ResetAllJournalCounter": string; + "Ui.Settings.Maintenance.ResetAllJournalCounterDesc": string; + "Ui.Settings.Maintenance.ResetJournalReceived": string; + "Ui.Settings.Maintenance.ResetJournalReceivedDesc": string; + "Ui.Settings.Maintenance.ResetJournalSent": string; + "Ui.Settings.Maintenance.ResetJournalSentDesc": string; + "Ui.Settings.Maintenance.ResetLocalSyncInfo": string; + "Ui.Settings.Maintenance.ResetLocalSyncInfoDesc": string; + "Ui.Settings.Maintenance.ResetReceived": string; + "Ui.Settings.Maintenance.ResetSentHistory": string; + "Ui.Settings.Maintenance.ResetThisDevice": string; + "Ui.Settings.Maintenance.ScheduleAndRestart": string; + "Ui.Settings.Maintenance.Scram": string; + "Ui.Settings.Maintenance.SendChunks": string; + "Ui.Settings.Maintenance.Syncing": string; + "Ui.Settings.Maintenance.WarningLockedReadyAction": string; + "Ui.Settings.Maintenance.WarningLockedReadyText": string; + "Ui.Settings.Maintenance.WarningLockedResolveAction": string; + "Ui.Settings.Maintenance.WarningLockedResolveText": string; + "Ui.Settings.Maintenance.WriteRedFlagAndRestart": string; + "Ui.Settings.Patches.CompatibilityConflict": string; + "Ui.Settings.Patches.CompatibilityDatabase": string; + "Ui.Settings.Patches.CompatibilityInternalApi": string; + "Ui.Settings.Patches.CompatibilityMetadata": string; + "Ui.Settings.Patches.CompatibilityRemote": string; + "Ui.Settings.Patches.CompatibilityTrouble": string; + "Ui.Settings.Patches.CurrentAdapter": string; + "Ui.Settings.Patches.DatabaseAdapter": string; + "Ui.Settings.Patches.DatabaseAdapterDesc": string; + "Ui.Settings.Patches.EdgeCaseBehaviour": string; + "Ui.Settings.Patches.EdgeCaseDatabase": string; + "Ui.Settings.Patches.EdgeCaseProcessing": string; + "Ui.Settings.Patches.IndexedDbWarning": string; + "Ui.Settings.Patches.MigratingToIdb": string; + "Ui.Settings.Patches.MigratingToIndexedDb": string; + "Ui.Settings.Patches.MigrationIdbCompleted": string; + "Ui.Settings.Patches.MigrationIdbCompletedFollowUp": string; + "Ui.Settings.Patches.MigrationIndexedDbCompleted": string; + "Ui.Settings.Patches.MigrationIndexedDbCompletedFollowUp": string; + "Ui.Settings.Patches.MigrationWarning": string; + "Ui.Settings.Patches.OperationToIdb": string; + "Ui.Settings.Patches.OperationToIndexedDb": string; + "Ui.Settings.Patches.Remediation": string; + "Ui.Settings.Patches.RemediationChanged": string; + "Ui.Settings.Patches.RemediationNoLimit": string; + "Ui.Settings.Patches.RemediationRestarting": string; + "Ui.Settings.Patches.RemediationRestartLater": string; + "Ui.Settings.Patches.RemediationRestartMessage": string; + "Ui.Settings.Patches.RemediationRestartNow": string; + "Ui.Settings.Patches.RemediationSuffixChanged": string; + "Ui.Settings.Patches.RemediationWithValue": string; + "Ui.Settings.Patches.RemoteDatabaseSunset": string; + "Ui.Settings.Patches.SwitchToIDB": string; + "Ui.Settings.Patches.SwitchToIndexedDb": string; + "Ui.Settings.PowerUsers.ConfigurationEncryption": string; + "Ui.Settings.PowerUsers.ConnectionTweak": string; + "Ui.Settings.PowerUsers.ConnectionTweakDesc": string; + "Ui.Settings.PowerUsers.Default": string; + "Ui.Settings.PowerUsers.Developer": string; + "Ui.Settings.PowerUsers.EncryptSensitiveConfig": string; + "Ui.Settings.PowerUsers.PromptPassphraseEveryLaunch": string; + "Ui.Settings.PowerUsers.UseCustomPassphrase": string; + "Ui.Settings.Remote.Activate": string; + "Ui.Settings.Remote.ActiveSuffix": string; + "Ui.Settings.Remote.AddConnection": string; + "Ui.Settings.Remote.AddRemoteDefaultName": string; + "Ui.Settings.Remote.ConfigureAndChangeRemote": string; + "Ui.Settings.Remote.ConfigureE2EE": string; + "Ui.Settings.Remote.ConfigureRemote": string; + "Ui.Settings.Remote.DeleteRemoteConfirm": string; + "Ui.Settings.Remote.DeleteRemoteTitle": string; + "Ui.Settings.Remote.DisplayName": string; + "Ui.Settings.Remote.DuplicateRemote": string; + "Ui.Settings.Remote.DuplicateRemoteSuffix": string; + "Ui.Settings.Remote.E2EEConfiguration": string; + "Ui.Settings.Remote.Export": string; + "Ui.Settings.Remote.FetchRemoteSettings": string; + "Ui.Settings.Remote.ImportConnection": string; + "Ui.Settings.Remote.ImportConnectionPrompt": string; + "Ui.Settings.Remote.ImportedCouchDb": string; + "Ui.Settings.Remote.ImportedRemote": string; + "Ui.Settings.Remote.MoreActions": string; + "Ui.Settings.Remote.PeerToPeerPanel": string; + "Ui.Settings.Remote.RemoteConfigurationPrefix": string; + "Ui.Settings.Remote.RemoteDatabases": string; + "Ui.Settings.Remote.RemoteName": string; + "Ui.Settings.Remote.RemoteNameCouchDb": string; + "Ui.Settings.Remote.RemoteNameP2P": string; + "Ui.Settings.Remote.RemoteNameS3": string; + "Ui.Settings.Remote.Rename": string; + "Ui.Settings.Selector.AddDefaultPatterns": string; + "Ui.Settings.Selector.CrossPlatform": string; + "Ui.Settings.Selector.Default": string; + "Ui.Settings.Selector.HiddenFiles": string; + "Ui.Settings.Selector.IgnorePatterns": string; + "Ui.Settings.Selector.NonSynchronisingFiles": string; + "Ui.Settings.Selector.NonSynchronisingFilesDesc": string; + "Ui.Settings.Selector.NormalFiles": string; + "Ui.Settings.Selector.OverwritePatterns": string; + "Ui.Settings.Selector.OverwritePatternsDesc": string; + "Ui.Settings.Selector.SynchronisingFiles": string; + "Ui.Settings.Selector.SynchronisingFilesDesc": string; + "Ui.Settings.Selector.TargetPatterns": string; + "Ui.Settings.Selector.TargetPatternsDesc": string; + "Ui.Settings.Setup.RerunWizardButton": string; + "Ui.Settings.Setup.RerunWizardDesc": string; + "Ui.Settings.Setup.RerunWizardName": string; + "Ui.Settings.SyncSettings.Fetch": string; + "Ui.Settings.SyncSettings.Merge": string; + "Ui.Settings.SyncSettings.Overwrite": string; + "Ui.SetupWizard.Common.Back": string; + "Ui.SetupWizard.Common.Cancel": string; + "Ui.SetupWizard.Common.ProceedSelectOption": string; + "Ui.SetupWizard.Intro.ExistingOption": string; + "Ui.SetupWizard.Intro.ExistingOptionDesc": string; + "Ui.SetupWizard.Intro.Guidance": string; + "Ui.SetupWizard.Intro.NewOption": string; + "Ui.SetupWizard.Intro.NewOptionDesc": string; + "Ui.SetupWizard.Intro.ProceedExisting": string; + "Ui.SetupWizard.Intro.ProceedNew": string; + "Ui.SetupWizard.Intro.Question": string; + "Ui.SetupWizard.Intro.Title": string; + "Ui.SetupWizard.OutroAskUserMode.CompatibleOption": string; + "Ui.SetupWizard.OutroAskUserMode.CompatibleOptionDesc": string; + "Ui.SetupWizard.OutroAskUserMode.ExistingOption": string; + "Ui.SetupWizard.OutroAskUserMode.ExistingOptionDesc": string; + "Ui.SetupWizard.OutroAskUserMode.Guidance": string; + "Ui.SetupWizard.OutroAskUserMode.NewOption": string; + "Ui.SetupWizard.OutroAskUserMode.NewOptionDesc": string; + "Ui.SetupWizard.OutroAskUserMode.ProceedApplySettings": string; + "Ui.SetupWizard.OutroAskUserMode.ProceedNext": string; + "Ui.SetupWizard.OutroAskUserMode.Question": string; + "Ui.SetupWizard.OutroAskUserMode.Title": string; + "Ui.SetupWizard.OutroNewUser.GuidancePrimary": string; + "Ui.SetupWizard.OutroNewUser.GuidanceWarning": string; + "Ui.SetupWizard.OutroNewUser.Important": string; + "Ui.SetupWizard.OutroNewUser.Proceed": string; + "Ui.SetupWizard.OutroNewUser.Question": string; + "Ui.SetupWizard.OutroNewUser.Title": string; + "Ui.SetupWizard.SelectExisting.Guidance": string; + "Ui.SetupWizard.SelectExisting.ManualOption": string; + "Ui.SetupWizard.SelectExisting.ManualOptionDesc": string; + "Ui.SetupWizard.SelectExisting.ProceedManual": string; + "Ui.SetupWizard.SelectExisting.ProceedQr": string; + "Ui.SetupWizard.SelectExisting.ProceedSetupUri": string; + "Ui.SetupWizard.SelectExisting.QrOption": string; + "Ui.SetupWizard.SelectExisting.QrOptionDesc": string; + "Ui.SetupWizard.SelectExisting.Question": string; + "Ui.SetupWizard.SelectExisting.SetupUriOption": string; + "Ui.SetupWizard.SelectExisting.SetupUriOptionDesc": string; + "Ui.SetupWizard.SelectExisting.Title": string; + "Ui.SetupWizard.SelectNew.Guidance": string; + "Ui.SetupWizard.SelectNew.ManualOption": string; + "Ui.SetupWizard.SelectNew.ManualOptionDesc": string; + "Ui.SetupWizard.SelectNew.ProceedManual": string; + "Ui.SetupWizard.SelectNew.ProceedSetupUri": string; + "Ui.SetupWizard.SelectNew.Question": string; + "Ui.SetupWizard.SelectNew.SetupUriOption": string; + "Ui.SetupWizard.SelectNew.SetupUriOptionDesc": string; + "Ui.SetupWizard.SelectNew.Title": string; + "Ui.SetupWizard.SetupRemote.BucketOption": string; + "Ui.SetupWizard.SetupRemote.BucketOptionDesc": string; + "Ui.SetupWizard.SetupRemote.CouchDbOptionDesc": string; + "Ui.SetupWizard.SetupRemote.Guidance": string; + "Ui.SetupWizard.SetupRemote.P2POption": string; + "Ui.SetupWizard.SetupRemote.P2POptionDesc": string; + "Ui.SetupWizard.SetupRemote.ProceedBucket": string; + "Ui.SetupWizard.SetupRemote.ProceedCouchDb": string; + "Ui.SetupWizard.SetupRemote.ProceedP2P": string; + "Ui.SetupWizard.SetupRemote.Title": string; + "Unique name between all synchronized devices. To edit this setting, please disable customization sync once.": string; + "Use a custom passphrase": string; + "Use a Setup URI (Recommended)": string; + "Use Custom HTTP Handler": string; + "Use dynamic iteration count": string; + "Use Segmented-splitter": string; + "Use splitting-limit-capped chunk splitter": string; + "Use the trash bin": string; + "Use timeouts instead of heartbeats": string; + username: string; + Username: string; + "Verbose Log": string; + "Verify all": string; + "Verify and repair all files": string; + "Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.": string; + "We cannot change the device name while this feature is enabled. Please disable this feature to change the device name.": string; + "We will now guide you through a few questions to simplify the synchronisation setup.": string; + "We will now proceed with the server configuration.": string; + "Welcome to Self-hosted LiveSync": string; + "When you save a file in the editor, start a sync automatically": string; + "Write credentials in the file": string; + "Write logs into the file": string; + "xxhash32 (Fast but less collision resistance)": string; + "xxhash64 (Fastest)": string; + "Yes, I want to add this device to my existing synchronisation": string; + "Yes, I want to set up a new synchronisation": string; + "You are adding this device to an existing synchronisation setup.": string; + }; +}; diff --git a/_types/lib/src/common/models/auth.type.d.ts b/_types/lib/src/common/models/auth.type.d.ts new file mode 100644 index 0000000..7d7281b --- /dev/null +++ b/_types/lib/src/common/models/auth.type.d.ts @@ -0,0 +1,41 @@ +export type CouchDBCredentials = BasicCredentials | JWTCredentials; +export type JWTAlgorithm = "HS256" | "HS512" | "ES256" | "ES512" | ""; +export type Credential = { + username: string; + password: string; +}; +export type BasicCredentials = { + username: string; + password: string; + type: "basic"; +}; +export type JWTCredentials = { + jwtAlgorithm: JWTAlgorithm; + jwtKey: string; + jwtKid: string; + jwtSub: string; + jwtExpDuration: number; + type: "jwt"; +}; +export interface JWTHeader { + alg: string; + typ: string; + kid?: string; +} +export interface JWTPayload { + sub: string; + exp: number; + iss?: string; + iat: number; + [key: string]: unknown; +} +export interface JWTParams { + header: JWTHeader; + payload: JWTPayload; + credentials: JWTCredentials; +} +export interface PreparedJWT { + header: JWTHeader; + payload: JWTPayload; + token: string; +} diff --git a/_types/lib/src/common/models/db.const.d.ts b/_types/lib/src/common/models/db.const.d.ts new file mode 100644 index 0000000..5c48fa6 --- /dev/null +++ b/_types/lib/src/common/models/db.const.d.ts @@ -0,0 +1,20 @@ +import type { DocumentID } from "./db.type"; +export declare const VERSIONING_DOCID: DocumentID; +export declare const MILESTONE_DOCID: DocumentID; +export declare const NODEINFO_DOCID: DocumentID; +export declare const SYNCINFO_ID: DocumentID; +export declare const EntryTypes: { + readonly NOTE_LEGACY: "notes"; + readonly NOTE_BINARY: "newnote"; + readonly NOTE_PLAIN: "plain"; + readonly INTERNAL_FILE: "internalfile"; + readonly CHUNK: "leaf"; + readonly CHUNK_PACK: "chunkpack"; + readonly VERSION_INFO: "versioninfo"; + readonly SYNC_INFO: "syncinfo"; + readonly SYNC_PARAMETERS: "sync-parameters"; + readonly MILESTONE_INFO: "milestoneinfo"; + readonly NODE_INFO: "nodeinfo"; +}; +export declare const NoteTypes: ("notes" | "newnote" | "plain")[]; +export declare const ChunkTypes: ("leaf" | "chunkpack")[]; diff --git a/_types/lib/src/common/models/db.definition.d.ts b/_types/lib/src/common/models/db.definition.d.ts new file mode 100644 index 0000000..5b4400e --- /dev/null +++ b/_types/lib/src/common/models/db.definition.d.ts @@ -0,0 +1,56 @@ +import type { MILESTONE_DOCID, NODEINFO_DOCID } from "./db.const"; +import type { AnyEntry, ChunkVersionRange, DatabaseEntry, EntryChunkPack, EntryLeaf, EntryTypes, EntryVersionInfo, LoadedEntry, MetaEntry } from "./db.type"; +import type { TweakValues } from "./tweak.definition"; +export type NodeKey = string; +export interface DeviceInfo { + /** + * Name of the device (Initially from deviceAndVaultName setting, configurable). + */ + device_name: string; + /** + * Vault name (From vaultName setting). + */ + vault_name: string; + /** + * Obsidian App version of the device. + */ + app_version: string; + /** + * Plugin version of the device. + */ + plugin_version: string; + progress: string; +} +export interface NodeData extends DeviceInfo { + /** + * Epoch time in milliseconds when the device last connected. + */ + last_connected: number; +} +export interface EntryMilestoneInfo extends DatabaseEntry { + _id: typeof MILESTONE_DOCID; + type: EntryTypes["MILESTONE_INFO"]; + created: number; + accepted_nodes: string[]; + node_info: { + [key: NodeKey]: NodeData; + }; + locked: boolean; + cleaned?: boolean; + node_chunk_info: { + [key: NodeKey]: ChunkVersionRange; + }; + tweak_values: { + [key: NodeKey]: TweakValues; + }; +} +export interface EntryNodeInfo extends DatabaseEntry { + _id: typeof NODEINFO_DOCID; + type: EntryTypes["NODE_INFO"]; + nodeid: string; + v20220607?: boolean; +} +export type EntryBody = AnyEntry; +export type EntryDoc = EntryBody | LoadedEntry | EntryLeaf | EntryVersionInfo | EntryMilestoneInfo | EntryNodeInfo | EntryChunkPack; +export type EntryDocResponse = EntryDoc & PouchDB.Core.IdMeta & PouchDB.Core.GetMeta; +export declare function isMetaEntry(entry: AnyEntry): entry is MetaEntry; diff --git a/_types/lib/src/common/models/db.type.d.ts b/_types/lib/src/common/models/db.type.d.ts new file mode 100644 index 0000000..e7f2252 --- /dev/null +++ b/_types/lib/src/common/models/db.type.d.ts @@ -0,0 +1,175 @@ +import type { TaggedType } from "octagonal-wheels/common/types"; +import type { EntryTypes, SYNCINFO_ID } from "./db.const"; +export type FilePath = TaggedType; +export type FilePathWithPrefixLC = TaggedType; +export type FilePathWithPrefix = TaggedType | FilePath | FilePathWithPrefixLC; +export type DocumentID = TaggedType; +export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes]; +export type EntryTypes = typeof EntryTypes; +export type EntryTypeNotes = EntryTypes["NOTE_BINARY"] | EntryTypes["NOTE_PLAIN"]; +export type EntryTypeNotesWithLegacy = EntryTypeNotes | EntryTypes["NOTE_LEGACY"]; +/** + * Represents an entry in the database. + */ +export interface DatabaseEntry { + /** + * The ID of the document. + */ + _id: DocumentID; + /** + * The revision of the document. + */ + _rev?: string; + /** + * Deleted flag. + */ + _deleted?: boolean; + /** + * Conflicts (if exists). + */ + _conflicts?: string[]; +} +/** + * Represents the base structure for an entry that represents a file. + */ +export interface EntryBase { + /** + * The creation time of the file. + */ + ctime: number; + /** + * The modification time of the file. + */ + mtime: number; + /** + * The size of the file. + */ + size: number; + /** + * Deleted flag. + */ + deleted?: boolean; +} +export type EdenChunk = { + data: string; + epoch: number; +}; +export type EntryWithEden = { + eden: Record; +}; +/** + * Represents the common fields for all database entries representing physical files. + */ +export interface FileEntryBase extends DatabaseEntry, EntryBase, EntryWithEden { + /** + * The path of the file. + */ + path: FilePathWithPrefix; +} +/** + * Represents an entry that contains children (chunk IDs). + */ +export interface EntryWithChildren { + /** + * Chunk IDs indicating the contents of the file. + */ + children: string[]; +} +/** + * Represents an entry that contains content data. + */ +export interface EntryWithData { + /** + * Contents / payload of the entry. + */ + data: T; +} +/** + * Represents an entry that contains document body text. + */ +export type EntryWithBody = EntryWithData; +/** + * Represents an entry that contains a binary Blob. + */ +export type EntryWithBlob = EntryWithData; +/** + * Represents a legacy note entry where file content is stored directly in the metadata. + */ +export interface NoteEntry extends FileEntryBase, EntryWithBody { + /** + * The type of the entry. + */ + type: EntryTypes["NOTE_LEGACY"]; +} +/** + * Represents a chunk-split binary file entry. + */ +export interface NewEntry extends FileEntryBase, EntryWithChildren { + /** + * The type of the entry. + */ + type: EntryTypes["NOTE_BINARY"]; +} +/** + * Represents a chunk-split plain text file entry. + */ +export interface PlainEntry extends FileEntryBase, EntryWithChildren { + /** + * The type of the entry. + */ + type: EntryTypes["NOTE_PLAIN"]; +} +/** + * Represents a customization / configuration file entry. + * @deprecated Use NewEntry or PlainEntry directly. + */ +export type InternalFileEntry = NewEntry; +/** + * Represents any file-related database entry. + */ +export type AnyEntry = NoteEntry | NewEntry | PlainEntry; +/** + * Represents a file entry after its contents have been loaded and assembled. + */ +export type LoadedEntry = AnyEntry & EntryWithBody & { + datatype: EntryTypeNotes; +}; +/** + * Represents a file entry prepared for saving. + */ +export type SavingEntry = AnyEntry & EntryWithBlob & { + datatype: EntryTypeNotes; +}; +/** + * Represents a metadata entry (chunked file entry) without full content. + */ +export type MetaEntry = NewEntry | PlainEntry; +/** + * Represents a leaf (chunk) document in the database. + */ +export interface EntryLeaf extends DatabaseEntry, EntryWithData { + type: EntryTypes["CHUNK"]; + isCorrupted?: boolean; +} +/** + * Represents a chunk pack document. + */ +export interface EntryChunkPack extends DatabaseEntry, EntryWithData { + type: EntryTypes["CHUNK_PACK"]; +} +export interface EntryVersionInfo extends DatabaseEntry { + type: EntryTypes["VERSION_INFO"]; + version: number; +} +export interface EntryHasPath { + path: FilePathWithPrefix | FilePath; +} +export interface ChunkVersionRange { + min: number; + max: number; + current: number; +} +export interface SyncInfo extends DatabaseEntry, EntryWithData { + _id: typeof SYNCINFO_ID; + type: EntryTypes["SYNC_INFO"]; +} diff --git a/_types/lib/src/common/models/diff.definition.d.ts b/_types/lib/src/common/models/diff.definition.d.ts new file mode 100644 index 0000000..62d66e5 --- /dev/null +++ b/_types/lib/src/common/models/diff.definition.d.ts @@ -0,0 +1,16 @@ +import type { AUTO_MERGED, CANCELLED, MISSING_OR_ERROR, NOT_CONFLICTED } from "./shared.const.symbols"; +export type diff_result_leaf = { + rev: string; + data: string; + ctime: number; + mtime: number; + deleted?: boolean; +}; +export type dmp_result = Array<[number, string]>; +export type diff_result = { + left: diff_result_leaf; + right: diff_result_leaf; + diff: dmp_result; +}; +export type DIFF_CHECK_RESULT_AUTO = typeof CANCELLED | typeof AUTO_MERGED | typeof NOT_CONFLICTED | typeof MISSING_OR_ERROR; +export type diff_check_result = DIFF_CHECK_RESULT_AUTO | diff_result; diff --git a/_types/lib/src/common/models/fileaccess.const.d.ts b/_types/lib/src/common/models/fileaccess.const.d.ts new file mode 100644 index 0000000..10a09b0 --- /dev/null +++ b/_types/lib/src/common/models/fileaccess.const.d.ts @@ -0,0 +1,7 @@ +export declare const CHeader = "h:"; +export declare const PSCHeader = "ps:"; +export declare const PSCHeaderEnd = "ps;"; +export declare const ICHeader = "i:"; +export declare const ICHeaderEnd = "i;"; +export declare const ICHeaderLength: number; +export declare const ICXHeader = "ix:"; diff --git a/_types/lib/src/common/models/fileaccess.type.d.ts b/_types/lib/src/common/models/fileaccess.type.d.ts new file mode 100644 index 0000000..ba750ea --- /dev/null +++ b/_types/lib/src/common/models/fileaccess.type.d.ts @@ -0,0 +1,83 @@ +import type { FilePath, FilePathWithPrefix } from "./db.type"; +export interface UXStat { + size: number; + mtime: number; + ctime: number; + type: "file" | "folder"; +} +/** + * Represents the common base properties for any filesystem object stub. + */ +export interface UXFileSystemStubBase { + name: string; + path: FilePath | FilePathWithPrefix; + deleted?: boolean; + isInternal?: boolean; +} +/** + * Represents a stub for a regular file. + */ +export interface UXFileInfoStub extends UXFileSystemStubBase { + stat: UXStat; + isFolder?: false; +} +/** + * Represents a complete file containing its binary body. + */ +export interface UXFileInfo extends UXFileInfoStub { + body: Blob; +} +export type UXAbstractInfoStub = UXFileInfoStub | UXFolderInfo; +/** + * Represents a stub for an internal/hidden file. + */ +export interface UXInternalFileInfoStub extends UXFileSystemStubBase { + isFolder?: false; + isInternal: true; + stat: undefined; +} +/** + * Represents information about a folder. + */ +export interface UXFolderInfo extends UXFileSystemStubBase { + isFolder: true; + children: UXFileInfoStub[]; + parent: FilePath | FilePathWithPrefix | undefined; +} +export interface UXDataWriteOptions { + /** + * Time of creation, represented as a unix timestamp, in milliseconds. + * Omit this if you want to keep the default behaviour. + * @public + * */ + ctime?: number; + /** + * Time of last modification, represented as a unix timestamp, in milliseconds. + * Omit this if you want to keep the default behaviour. + * @public + * */ + mtime?: number; +} +export type CacheData = string | ArrayBuffer; +export type FileEventType = "CREATE" | "DELETE" | "CHANGED" | "INTERNAL"; +export interface FileEventArgs { + file: UXFileInfoStub | UXInternalFileInfoStub; + cache?: CacheData; + oldPath?: string; + ctx?: unknown; +} +export interface FileEventItem { + type: FileEventType; + args: FileEventArgs; + key: string; + skipBatchWait?: boolean; + cancelled?: boolean; + batched?: boolean; +} +export interface FileWithFileStat extends Omit { + path: FilePath; +} +export interface FileWithStatAsProp { + path: FilePath; + stat: Omit; +} diff --git a/_types/lib/src/common/models/redflag.const.d.ts b/_types/lib/src/common/models/redflag.const.d.ts new file mode 100644 index 0000000..6245223 --- /dev/null +++ b/_types/lib/src/common/models/redflag.const.d.ts @@ -0,0 +1,32 @@ +import type { FilePath } from "./db.type"; +export declare const PREFIXMD_LOGFILE = "livesync_log_"; +export declare const PREFIXMD_LOGFILE_UC = "LIVESYNC_LOG_"; +export declare const FlagFilesOriginal: { + readonly SUSPEND_ALL: FilePath; + readonly REBUILD_ALL: FilePath; + readonly FETCH_ALL: FilePath; +}; +export declare const FlagFilesHumanReadable: { + readonly REBUILD_ALL: FilePath; + readonly FETCH_ALL: FilePath; +}; +/** + * @deprecated Use `FlagFilesOriginal.SUSPEND_ALL` instead. + */ +export declare const FLAGMD_REDFLAG: FilePath; +/** + * @deprecated Use `FlagFilesHumanReadable.REBUILD_ALL` instead. + */ +export declare const FLAGMD_REDFLAG2: FilePath; +/** + * @deprecated Use `FlagFilesHumanReadable.FETCH_ALL` instead. + */ +export declare const FLAGMD_REDFLAG2_HR: FilePath; +/** + * @deprecated Use `FlagFilesOriginal.FETCH_ALL` instead. + */ +export declare const FLAGMD_REDFLAG3: FilePath; +/** + * @deprecated Use `FlagFilesHumanReadable.FETCH_ALL` instead. + */ +export declare const FLAGMD_REDFLAG3_HR: FilePath; diff --git a/_types/lib/src/common/models/setting.const.d.ts b/_types/lib/src/common/models/setting.const.d.ts new file mode 100644 index 0000000..40e8028 --- /dev/null +++ b/_types/lib/src/common/models/setting.const.d.ts @@ -0,0 +1,49 @@ +export declare const SETTING_VERSION_INITIAL = 0; +export declare const SETTING_VERSION_SUPPORT_CASE_INSENSITIVE = 10; +export declare const CURRENT_SETTING_VERSION = 10; +export declare const RemoteTypes: { + readonly REMOTE_COUCHDB: ""; + readonly REMOTE_MINIO: "MINIO"; + readonly REMOTE_P2P: "ONLY_P2P"; +}; +export declare const REMOTE_COUCHDB: ""; +export declare const REMOTE_MINIO: "MINIO"; +export declare const REMOTE_P2P: "ONLY_P2P"; +export declare const E2EEAlgorithmNames: { + readonly "": "V1: Legacy"; + readonly v2: "V2: AES-256-GCM With HKDF"; + readonly forceV1: "Force-V1: Force Legacy (Not recommended)"; +}; +export declare const E2EEAlgorithms: { + readonly V1: ""; + readonly V2: "v2"; + readonly ForceV1: "forceV1"; +}; +export declare const HashAlgorithms: { + readonly XXHASH32: "xxhash32"; + readonly XXHASH64: "xxhash64"; + readonly MIXED_PUREJS: "mixed-purejs"; + readonly SHA1: "sha1"; + readonly LEGACY: ""; +}; +export declare const ChunkAlgorithmNames: { + readonly v1: "V1: Legacy"; + readonly v2: "V2: Simple (Default)"; + readonly "v2-segmenter": "V2.5: Lexical chunks"; + readonly "v3-rabin-karp": "V3: Fine deduplication"; +}; +export declare const ChunkAlgorithms: { + readonly V1: "v1"; + readonly V2: "v2"; + readonly V2Segmenter: "v2-segmenter"; + readonly RabinKarp: "v3-rabin-karp"; +}; +export declare const MODE_SELECTIVE = 0; +export declare const MODE_AUTOMATIC = 1; +export declare const MODE_PAUSED = 2; +export declare const MODE_SHINY = 3; +export declare const NetworkWarningStyles: { + readonly BANNER: ""; + readonly ICON: "icon"; + readonly HIDDEN: "hidden"; +}; diff --git a/_types/lib/src/common/models/setting.const.defaults.d.ts b/_types/lib/src/common/models/setting.const.defaults.d.ts new file mode 100644 index 0000000..4778d38 --- /dev/null +++ b/_types/lib/src/common/models/setting.const.defaults.d.ts @@ -0,0 +1,3 @@ +import { type ObsidianLiveSyncSettings, type P2PSyncSetting } from "./setting.type"; +export declare const P2P_DEFAULT_SETTINGS: P2PSyncSetting; +export declare const DEFAULT_SETTINGS: ObsidianLiveSyncSettings; diff --git a/_types/lib/src/common/models/setting.const.preferred.d.ts b/_types/lib/src/common/models/setting.const.preferred.d.ts new file mode 100644 index 0000000..69f879c --- /dev/null +++ b/_types/lib/src/common/models/setting.const.preferred.d.ts @@ -0,0 +1,5 @@ +import type { ObsidianLiveSyncSettings } from "./setting.type"; +export declare const PREFERRED_BASE: Partial; +export declare const PREFERRED_SETTING_CLOUDANT: Partial; +export declare const PREFERRED_SETTING_SELF_HOSTED: Partial; +export declare const PREFERRED_JOURNAL_SYNC: Partial; diff --git a/_types/lib/src/common/models/setting.const.qr.d.ts b/_types/lib/src/common/models/setting.const.qr.d.ts new file mode 100644 index 0000000..06e6fa2 --- /dev/null +++ b/_types/lib/src/common/models/setting.const.qr.d.ts @@ -0,0 +1,2 @@ +import type { ObsidianLiveSyncSettings } from "./setting.type"; +export declare const KeyIndexOfSettings: Record; diff --git a/_types/lib/src/common/models/setting.type.d.ts b/_types/lib/src/common/models/setting.type.d.ts new file mode 100644 index 0000000..f2fc703 --- /dev/null +++ b/_types/lib/src/common/models/setting.type.d.ts @@ -0,0 +1,893 @@ +import type { ChunkAlgorithms, E2EEAlgorithms, HashAlgorithms, MODE_AUTOMATIC, MODE_PAUSED, MODE_SELECTIVE, MODE_SHINY, RemoteTypes } from "./setting.const"; +import type { I18N_LANGS } from "@lib/common/rosetta"; +import type { CustomRegExpSourceList } from "./shared.type.util"; +import type { JWTAlgorithm } from "./auth.type"; +/** + * Represents the connection details required to connect to a CouchDB instance. + */ +export interface CouchDBConnection { + /** + * The URI of the CouchDB instance. + */ + couchDB_URI: string; + /** + * The username to use when connecting to the CouchDB instance. + */ + couchDB_USER: string; + /** + * The password to use when connecting to the CouchDB instance. + */ + couchDB_PASSWORD: string; + /** + * The name of the database to use. + */ + couchDB_DBNAME: string; + /** + * e.g. `x-some-header: some-value\n x-some-header2: some-value2` + */ + couchDB_CustomHeaders: string; + useJWT: boolean; + jwtAlgorithm: JWTAlgorithm; + jwtKey: string; + jwtKid: string; + jwtSub: string; + jwtExpDuration: number; + /** + * Use Request API to avoid `inevitable` CORS problem. + * Seems stable, so promoted to the normal setting. + */ + useRequestAPI: boolean; +} +/** + * Interface representing the settings for periodic replication. + */ +interface PeriodicReplicationSettings { + /** + * Indicates whether periodic replication is enabled. + */ + periodicReplication: boolean; + /** + * The interval, in milliseconds, at which periodic replication occurs. + */ + periodicReplicationInterval: number; +} +export type ConfigPassphraseStore = "" | "LOCALSTORAGE" | "ASK_AT_LAUNCH"; +/** + * Represents the user settings that are encrypted. + */ +interface EncryptedUserSettings { + /** + * The store for the configuration passphrase. + */ + configPassphraseStore: ConfigPassphraseStore; + /** + * The encrypted passphrase used for E2EE. + */ + encryptedPassphrase: string; + /** + * The encrypted connection details for CouchDB. + */ + encryptedCouchDBConnection: string; +} +/** + * Interface representing the settings for different sync invocation methods. + */ +interface SyncMethodSettings { + /** + * Synchronise in Live. This is an exclusive setting against other sync methods. + */ + liveSync: boolean; + /** + * automatically run sync on save. + * File modification will trigger the sync, even if the file is not changed on the editor. + */ + syncOnSave: boolean; + /** + * automatically run sync on starting the plug-in. + */ + syncOnStart: boolean; + /** + * automatically run sync on opening a file. + */ + syncOnFileOpen: boolean; + /** + * automatically run sync on editor save. + * Different from syncOnSave, this is only reacts to the editor save event. + */ + syncOnEditorSave: boolean; + /** + * The minimum delay between synchronisation operations (in milliseconds). + * If the operation is triggered before this delay, the operation will be delayed until the delay is over, and executed as a single operation. + */ + syncMinimumInterval: number; +} +/** + * Interface representing the settings for file handling. + */ +interface FileHandlingSettings { + /** + * Use trash instead of actually delete. + */ + trashInsteadDelete: boolean; + /** + * Do not delete the folder even if it has got empty. + */ + doNotDeleteFolder: boolean; + /** + * Thinning out the changes and make a single change for the same file. + */ + batchSave: boolean; + batchSaveMinimumDelay: number; + batchSaveMaximumDelay: number; + /** + * Maximum size of the file to be synchronized (in MB). + */ + syncMaxSizeInMB: number; + /** + * Use ignore files. + */ + useIgnoreFiles: boolean; + /** + * Ignore files pattern, i,e, `.gitignore, .obsidianignore` (This should be separated by comma) + */ + ignoreFiles: string; + /** + * Do not prevent write if the size is mismatched. + */ + processSizeMismatchedFiles: boolean; +} +/** + * Interface representing the settings for Hidden File Sync. + */ +interface InternalFileSettings { + /** + * Synchronise internal files. + */ + syncInternalFiles: boolean; + /** + * Scan internal files before replication. + */ + syncInternalFilesBeforeReplication: boolean; + /** + * Interval for scanning internal files (in seconds). + */ + syncInternalFilesInterval: number; + /** + * Ignore patterns for internal files. + * (Comma separated list of regular expressions) + */ + syncInternalFilesIgnorePatterns: CustomRegExpSourceList<",">; + /** + * Limit patterns for internal files. + */ + syncInternalFilesTargetPatterns: CustomRegExpSourceList<",">; + /** + * Enable watch internal file changes (This option uses the unexposed API) + */ + watchInternalFileChanges: boolean; + /** + * Suppress notification of hidden files change. + */ + suppressNotifyHiddenFilesChange: boolean; + /** + * Overwrite instead of merging patterns for internal files. + */ + syncInternalFileOverwritePatterns: CustomRegExpSourceList<",">; +} +export type SYNC_MODE = typeof MODE_SELECTIVE | typeof MODE_AUTOMATIC | typeof MODE_PAUSED | typeof MODE_SHINY; +export interface PluginSyncSettingEntry { + key: string; + mode: SYNC_MODE; + files: string[]; +} +/** + * Interface representing the settings for plugin synchronisation. + */ +interface PluginSyncSettings { + /** + * Indicates whether plugin synchronisation is enabled. + */ + usePluginSync: boolean; + /** + * Indicates whether plugin settings synchronisation is enabled. + */ + usePluginSettings: boolean; + /** + * Indicates whether to show the device's own plugins. + */ + showOwnPlugins: boolean; + /** + * Indicates whether to automatically scan plugins. + */ + autoSweepPlugins: boolean; + /** + * Indicates whether to periodically scan plugins automatically. + */ + autoSweepPluginsPeriodic: boolean; + /** + * Indicates whether to notify when a plugin or setting is updated. + */ + notifyPluginOrSettingUpdated: boolean; + /** + * The name of the device and vault. + * This is used to identify the device and vault among synchronised devices and vaults. + * Hence, this should be unique among devices and vaults. + */ + deviceAndVaultName: string; + /** + * Indicates whether the v2 of plugin synchronisation is enabled. + */ + usePluginSyncV2: boolean; + /** + * Indicates whether additional plugin synchronisation settings are enabled. + * This setting is hidden from the UI. + */ + usePluginEtc: boolean; + /** + * Extended settings for plugin synchronisation. + */ + pluginSyncExtendedSetting: Record; +} +/** + * Interface representing the user interface settings. + */ +interface UISettings { + /** + * Indicates whether verbose logging has been enabled. + */ + showVerboseLog: boolean; + /** + * Indicates whether less information should be shown in the log. + */ + lessInformationInLog: boolean; + /** + * Indicates whether longer status line should be shown inside the editor. + */ + showLongerLogInsideEditor: boolean; + /** + * Indicates whether the status line should be shown on the editor. + */ + showStatusOnEditor: boolean; + /** + * Indicates whether the status line should be shown on the status bar. + */ + showStatusOnStatusbar: boolean; + /** + * Indicates whether only icons instead of status line should be shown on the editor. + */ + showOnlyIconsOnEditor: boolean; + /** + * Hide File warning notice bar. + */ + hideFileWarningNotice: boolean; + /** + * How to display connection error warnings. + * "banner" shows the full banner, "icon" shows only an icon, "hidden" suppresses entirely. + */ + networkWarningStyle: "" | "icon" | "hidden"; + /** + * The language to be used for display. + */ + displayLanguage: I18N_LANGS; +} +/** + * Interface representing the settings for mode of exposing advanced things. + */ +interface ModeSettings { + /** + * Indicates whether the advanced mode is enabled. + */ + useAdvancedMode: boolean; + /** + * Indicates whether the power user mode is enabled. + */ + usePowerUserMode: boolean; + /** + * Indicates whether the edge case mode is enabled. + */ + useEdgeCaseMode: boolean; +} +/** + * Interface representing the settings for debug mode. + */ +interface DebugModeSettings { + /** + * Indicates whether the debug tools of Self-hosted LiveSync are enabled. + */ + enableDebugTools: boolean; + /** + * Indicates whether to write log to the file. + */ + writeLogToTheFile: boolean; +} +/** + * Interface representing additional tweak settings. + */ +interface ExtraTweakSettings { + /** + * The threshold value for notifying about the size of remote storage. + * When the size of the remote storage exceeds this threshold, a notification will be triggered. + */ + notifyThresholdOfRemoteStorageSize: number; +} +/** + * Interface representing the settings for beta tweaks. + */ +interface BetaTweakSettings { + /** + * Indicates whether to disable the WebWorker for generating chunks. + */ + disableWorkerForGeneratingChunks: boolean; + /** + * Indicates whether to process small files in the UI thread. + */ + processSmallFilesInUIThread: boolean; +} +/** + * Interface representing the settings for synchronising settings via file. + */ +interface SettingSyncSettings { + /** + * The file path where the settings is stored. + */ + settingSyncFile: string; + /** + * Indicates whether to write credentials for settings synchronising. + */ + writeCredentialsForSettingSync: boolean; + /** + * Indicates whether to notify all settings synchronising files events. + */ + notifyAllSettingSyncFile: boolean; +} +/** + * Represents settings that are considered obsolete and are not configurable from the UI. + */ +interface ObsoleteSettings { + /** + * Saving delay (in milliseconds). + */ + savingDelay: number; + /** + * Garbage collection delay (in milliseconds). Now, no longer GC is implemented. + */ + gcDelay: number; + /** + * Skip older files on sync. No effect now. + */ + skipOlderFilesOnSync: boolean; + /** + * Use the IndexedDB adapter. Now always true. Should be. + */ + useIndexedDBAdapter: boolean; +} +/** + * Interface representing some data stored in the settings for the plugin. + */ +interface DataOnSettings { + /** + * VersionUp flash message which is shown when some incompatible changes are made during the update. + */ + versionUpFlash: string; + /** + * Setting file version, to migrate the settings. + */ + settingVersion: number; + /** + * Indicates whether the setting of the plug-in is configured once. + */ + isConfigured?: boolean; + /** + * The user-last-read version number. + */ + lastReadUpdates: number; + /** + * The last checked version by the doctor. + */ + doctorProcessedVersion: string; +} +/** + * Interface representing the settings for a safety valve mechanism. + */ +interface SafetyValveSettings { + /** + * Indicates whether file watching should be suspended. + */ + suspendFileWatching: boolean; + /** + * Indicates whether parsing and reflecting of replication results should be suspended. + */ + suspendParseReplicationResult: boolean; + /** + * Indicates whether suspension should be avoided during fetching operations. + */ + doNotSuspendOnFetching: boolean; + /** + * Maximum file modification time applied to reflected file events + */ + maxMTimeForReflectEvents: number; +} +/** + * Represents the settings required to synchronise with a bucket. + */ +export interface BucketSyncSetting { + /** + * The access key to use when connecting to the bucket. + */ + accessKey: string; + /** + * The secret to use when connecting to the bucket. + */ + secretKey: string; + /** + * The name of bucket to use. + */ + bucket: string; + /** + * The region of the bucket. + */ + region: string; + /** + * The endpoint of the bucket. + */ + endpoint: string; + /** + * Indicates whether to use a custom request handler. + * (This is for CORS issue). + */ + useCustomRequestHandler: boolean; + bucketCustomHeaders: string; + /** + * The prefix to use for the bucket (e.g., "my-bucket/", means mostly like a folder). + */ + bucketPrefix: string; + /** + * Indicates whether to force path style access. + */ + forcePathStyle: boolean; +} +export interface LocalDBSettings { + /** + * Indicates whether to use the IndexedDB adapter for the local database. + * @deprecated + */ + useIndexedDBAdapter: boolean; +} +export type RemoteType = (typeof RemoteTypes)[keyof typeof RemoteTypes]; +export declare enum AutoAccepting { + NONE = 0, + ALL = 1 +} +export interface P2PConnectionInfo { + /** + * Indicates whether P2P connection is enabled. + */ + P2P_Enabled: boolean; + /** + * Nostr relay server URL. (Comma separated list) + * This is only for the channelling server to establish for the P2P connection. + * No data is transferred through this server. + */ + P2P_relays: string; + /** + * The room ID for `your devices`. This should be unique among the users. + * (Or, lines will be got mixed up). + */ + P2P_roomID: string; + /** + * The passphrase for your devices. + * It can be empty, but it will help you if you have a duplicate Room ID. + */ + P2P_passphrase: string; + /** + * The Application ID for the P2P connection. + * This is used to identify the application using the P2P network. + * In Self-hosted LiveSync, fixed to "self-hosted-livesync". + */ + P2P_AppID: string; + /** + * Indicates whether to auto-start the P2P connection on launch. + */ + P2P_AutoStart: boolean; + /** + * Indicates whether to automatically broadcast changes to connected peers. + */ + P2P_AutoBroadcast: boolean; + /** + * The name of the device peer (This only for editing-setting purpose, not saved in the actual setting file, due to avoid setting-sync issues). + */ + P2P_DevicePeerName?: string; + /** + * The TURN server URLs for the P2P connection. (Comma separated list) + */ + P2P_turnServers: string; + /** + * The TURN username for the P2P connection. + */ + P2P_turnUsername: string; + /** + * The TURN credential (password, secret, etc...) for the P2P connection. + */ + P2P_turnCredential: string; + /** + * Use Diagnostic Wrapper for RTCPeerConnection to collect statistics. + */ + P2P_useDiagRTC?: boolean; +} +export interface P2PSyncSetting extends P2PConnectionInfo { + P2P_AutoAccepting: AutoAccepting; + P2P_AutoSyncPeers: string; + P2P_AutoWatchPeers: string; + P2P_SyncOnReplication: string; + P2P_RebuildFrom: string; + P2P_AutoAcceptingPeers: string; + P2P_AutoDenyingPeers: string; + P2P_IsHeadless?: boolean; +} +/** + * Interface representing the settings for a remote type. + */ +export interface RemoteTypeSettings { + /** + * The type of the remote. + */ + remoteType: RemoteType; +} +export type E2EEAlgorithm = (typeof E2EEAlgorithms)[keyof typeof E2EEAlgorithms] | ""; +/** + * Represents the settings used for End-to-End encryption. + */ +export interface EncryptionSettings { + /** + * Indicates whether E2EE is enabled. + */ + encrypt: boolean; + /** + * The passphrase used for E2EE. + */ + passphrase: string; + /** + * Indicates whether path obfuscation is used. + * If not, the path will be stored as it is, as the document ID. + */ + usePathObfuscation: boolean; + /** + * The algorithm used for hashing the passphrase. + * This is used for E2EE. + */ + E2EEAlgorithm: E2EEAlgorithm; +} +export type HashAlgorithm = (typeof HashAlgorithms)[keyof typeof HashAlgorithms]; +export type ChunkSplitterVersion = (typeof ChunkAlgorithms)[keyof typeof ChunkAlgorithms] | ""; +/** + * Interface representing the settings for chunk processing. + */ +interface ChunkSettings { + /** + * The algorithm used for hashing chunks. + */ + hashAlg: HashAlgorithm; + /** + * The minimum size of a chunk in chars. + */ + minimumChunkSize: number; + /** + * The custom size of a chunk. + * Note: This value used as a coefficient for the normal chunk size. + */ + customChunkSize: number; + /** + * The threshold for considering a line as long. + * (Not respected in v0.24.x). + */ + longLineThreshold: number; + /** + * Flag indicating whether to use a segmenter for chunking. + * @deprecated use chunkSplitterVersion instead. + */ + useSegmenter: boolean; + /** + * Flag indicating whether to enable version 2 of the chunk splitter. + * @deprecated use chunkSplitterVersion instead. + */ + enableChunkSplitterV2: boolean; + /** + * Flag indicating whether to avoid using a fixed revision for chunks. + */ + doNotUseFixedRevisionForChunks: boolean; + /** + * The version of the chunk splitter to use. + */ + chunkSplitterVersion: ChunkSplitterVersion; +} +/** + * Settings for on-demand chunk fetching. + */ +interface OnDemandChunkSettings { + /** + * Indicates whether chunks should be fetch online. (means replication transfers only metadata). + */ + readChunksOnline: boolean; + /** + * Indicates whether to use only local chunks without fetching online. + */ + useOnlyLocalChunk: boolean; + /** + * The number of concurrent chunk reads allowed when fetching online. + */ + concurrencyOfReadChunksOnline: number; + /** + * The minimum interval (in milliseconds) between consecutive online chunk fetching. + */ + minimumIntervalOfReadChunksOnline: number; +} +/** + * Configuration settings for Eden. + */ +interface EdenSettings { + /** + * Indicates whether Eden is enabled. + */ + useEden: boolean; + /** + * The maximum number of chunks allowed in Eden. + */ + maxChunksInEden: number; + /** + * The maximum total length allowed in Eden. + */ + maxTotalLengthInEden: number; + /** + * The maximum age allowed in Eden. + */ + maxAgeInEden: number; +} +/** + * Interface representing obsolete settings for an remote database. + */ +interface ObsoleteRemoteDBSettings { + /** + * Indicates whether to check the integrity of the data on save. + */ + checkIntegrityOnSave: boolean; + /** + * Indicates whether to use history tracking. + * (Now always true) + */ + useHistory: boolean; + /** + * Indicates whether to disable using API of Obsidian. + * (Now always true: Note: Obsidian cannot handle multiple requests at the same time). + */ + disableRequestURI: boolean; + /** + * Indicates whether to send data in bulk chunks. + */ + sendChunksBulk: boolean; + /** + * The maximum size of the bulk chunks to be sent. + */ + sendChunksBulkMaxSize: number; + /** + * Indicates whether to use a dynamic iteration count. + */ + useDynamicIterationCount: boolean; + /** + * Indicates weather to pace the replication processing interval. + * Now (v0.24.x) not be respected. + */ + doNotPaceReplication: boolean; +} +/** + * Interface representing the settings for beta tweaks for the remote database. + */ +interface BetaRemoteDBSettings { + /** + * Indicates whether compression is enabled for the remote database. + */ + enableCompression: boolean; +} +/** + * Interface representing the some data stored on the settings. + */ +interface DataOnRemoteDBSettings { + /** + * VersionUp flash message which is shown when some incompatible changes are made during the update. + */ + versionUpFlash: string; + /** + * Unix timestamp (ms) of the latest tweak update. + * Used to determine which side has newer tweak values. + */ + tweakModified: number | undefined; +} +/** + * Interface representing the settings for replication. + */ +interface ReplicationSetting { + /** + * The maximum number of documents to be processed in a batch. + */ + batch_size: number; + /** + * The maximum number of batches to be processed. + */ + batches_limit: number; +} +/** + * Interface representing the settings for targetting files. + */ +interface FileHandlingSettings { + /** + * The regular expression for files to be synchronised. + */ + syncOnlyRegEx: CustomRegExpSourceList<"|[]|">; + /** + * The regular expression for files to be ignored during synchronisation. + */ + syncIgnoreRegEx: CustomRegExpSourceList<"|[]|">; +} +/** + * Interface representing the settings for processing behaviour. + */ +interface ProcessingBehaviourSettings { + /** + * Hash cache maximum count. + */ + hashCacheMaxCount: number; + /** + * Hash cache maximum amount. + */ + hashCacheMaxAmount: number; +} +/** + * Interface representing the settings for remote database tweaks. + */ +interface RemoteDBTweakSettings { + /** + * Indicates whether to ignore the version check. + */ + ignoreVersionCheck: boolean; + /** + * Indicates whether to ignore and continue syncing even if the configuration-mismatch is detected. + * (Note: Mismatched settings can lead to inappropriate de-duplication, leading to storage wastage and increased traffic). + */ + disableCheckingConfigMismatch: boolean; + /** + * Automatically accepts compatible-but-lossy tweak mismatches. + * If undefined, the feature is not configured yet. + */ + autoAcceptCompatibleTweak: boolean | undefined; +} +/** + * Interface representing the settings for optional and not exposed remote database settings. + */ +interface OptionalAndNotExposedRemoteDBSettings { + /** + * Indicates whether to accept empty passphrase. + * This not meant to `Not be encrypted`, but `Be encrypted with empty passphrase`. + */ + permitEmptyPassphrase: boolean; +} +/** + * Interface representing the settings for cross-platform interoperability. + */ +interface CrossPlatformInteroperabilitySettings { + /** + * Indicates whether to handle filename case sensitively. + */ + handleFilenameCaseSensitive: boolean; +} +/** + * Interface representing the settings for conflict handling. + */ +interface ConflictHandlingSettings { + /** + * Indicates whether to check conflicts only on file open. + */ + checkConflictOnlyOnOpen: boolean; + /** + * Indicates whether to show the merge dialog only on active file. + */ + showMergeDialogOnlyOnActive: boolean; +} +/** + * Settings that define the behavior of the merge process. + */ +interface MergeBehaviourSettings { + /** + * Indicates whether to synchronise after merging. + */ + syncAfterMerge: boolean; + /** + * Determines if conflicts should be resolved by choosing the newer file. + */ + resolveConflictsByNewerFile: boolean; + /** + * Specifies whether to write documents even if there are conflicts. + */ + writeDocumentsIfConflicted: boolean; + /** + * Disables automatic merging of markdown files. + */ + disableMarkdownAutoMerge: boolean; +} +/** + * Configuration settings for handling edge cases in the application. + */ +interface EdgeCaseHandlingSettings { + /** + * An optional suffix to append to the database name after the vault name. + */ + additionalSuffixOfDatabaseName: string | undefined; + /** + * Flag to disable the worker thread for generating chunks. + */ + disableWorkerForGeneratingChunks: boolean; + /** + * Flag to process small files in the UI thread instead of a worker thread. + */ + processSmallFilesInUIThread: boolean; + /** + * Indicates whether to use timeout for PouchDB replication. + */ + useTimeouts: boolean; +} +/** + * Configuration settings for handling deleted files. + */ +interface DeletedFileMetadataSettings { + /** + * Indicates whether to delete metadata of deleted files. + */ + deleteMetadataOfDeletedFiles: boolean; + /** + * The number of days to wait before automatically deleting metadata of deleted files. + */ + automaticallyDeleteMetadataOfDeletedFiles: number; +} +/** + * Represents a single remote configuration. + */ +export interface RemoteConfiguration { + /** + * Unique identifier for this configuration. + */ + id: string; + /** + * Display name for the configuration. + */ + name: string; + /** + * The connection string (URI) for the remote. + * This may be an encrypted string if configPassphraseStore is set. + */ + uri: string; + /** + * Indicates whether this configuration is encrypted. + */ + isEncrypted: boolean; +} +export interface RemoteConfigurations { + /** + * The list of remote configurations. + */ + remoteConfigurations: Record; + /** + * The ID of the currently active remote configuration. + */ + activeConfigurationId: string; + /** + * The ID of the active remote configuration dedicated for P2P features. + * If empty, P2P features should request explicit selection from the user. + */ + P2P_ActiveRemoteConfigurationId: string; +} +interface ObsidianLiveSyncSettings_PluginSetting extends SyncMethodSettings, UISettings, FileHandlingSettings, MergeBehaviourSettings, EncryptedUserSettings, PeriodicReplicationSettings, InternalFileSettings, PluginSyncSettings, ModeSettings, ExtraTweakSettings, BetaTweakSettings, ObsoleteSettings, DebugModeSettings, SettingSyncSettings, SafetyValveSettings, DataOnSettings, RemoteConfigurations { +} +export type RemoteDBSettings = CouchDBConnection & BucketSyncSetting & RemoteTypeSettings & EncryptionSettings & ChunkSettings & EdenSettings & DataOnRemoteDBSettings & ObsoleteRemoteDBSettings & OnDemandChunkSettings & BetaRemoteDBSettings & ReplicationSetting & RemoteDBTweakSettings & FileHandlingSettings & ProcessingBehaviourSettings & OptionalAndNotExposedRemoteDBSettings & CrossPlatformInteroperabilitySettings & ConflictHandlingSettings & EdgeCaseHandlingSettings & DeletedFileMetadataSettings & P2PSyncSetting & RemoteConfigurations; +export type ObsidianLiveSyncSettings = ObsidianLiveSyncSettings_PluginSetting & RemoteDBSettings & LocalDBSettings; +export interface HasSettings> { + settings: T; +} +export {}; diff --git a/_types/lib/src/common/models/shared.const.behabiour.d.ts b/_types/lib/src/common/models/shared.const.behabiour.d.ts new file mode 100644 index 0000000..870ab6c --- /dev/null +++ b/_types/lib/src/common/models/shared.const.behabiour.d.ts @@ -0,0 +1,28 @@ +export declare const MAX_DOC_SIZE = 1000; +export declare const MAX_DOC_SIZE_BIN = 102400; +export declare const VER = 12; +export declare const RECENT_MODIFIED_DOCS_QTY = 30; +export declare const LEAF_WAIT_TIMEOUT = 30000; +export declare const LEAF_WAIT_ONLY_REMOTE = 5000; +export declare const LEAF_WAIT_TIMEOUT_SEQUENTIAL_REPLICATOR = 5000; +export declare const REPLICATION_BUSY_TIMEOUT = 3000000; +export declare const SALT_OF_PASSPHRASE = "rHGMPtr6oWw7VSa3W3wpa8fT8U"; +export declare const SALT_OF_ID = "a83hrf7f\u0003y7sa8g31"; +export declare const SEED_MURMURHASH = 305419896; +export declare const IDPrefixes: { + Obfuscated: string; + Chunk: string; + EncryptedChunk: string; +}; +/** + * @deprecated Use `IDPrefixes.Obfuscated` instead. + */ +export declare const PREFIX_OBFUSCATED = "f:"; +/** + * @deprecated Use `IDPrefixes.Chunk` instead. + */ +export declare const PREFIX_CHUNK = "h:"; +/** + * @deprecated Use `IDPrefixes.EncryptedChunk` instead. + */ +export declare const PREFIX_ENCRYPTED_CHUNK = "h:+"; diff --git a/_types/lib/src/common/models/shared.const.d.ts b/_types/lib/src/common/models/shared.const.d.ts new file mode 100644 index 0000000..6b4919b --- /dev/null +++ b/_types/lib/src/common/models/shared.const.d.ts @@ -0,0 +1,5 @@ +export declare const SETTING_KEY_P2P_DEVICE_NAME = "p2p_device_name"; +export declare const configURIBase = "obsidian://setuplivesync?settings="; +export declare const configURIBaseQR = "obsidian://setuplivesync?settingsQR="; +export declare const SuffixDatabaseName = "-livesync-v2"; +export declare const ExtraSuffixIndexedDB = "-indexeddb"; diff --git a/_types/lib/src/common/models/shared.const.symbols.d.ts b/_types/lib/src/common/models/shared.const.symbols.d.ts new file mode 100644 index 0000000..b04cf2b --- /dev/null +++ b/_types/lib/src/common/models/shared.const.symbols.d.ts @@ -0,0 +1,9 @@ +export declare const CANCELLED: unique symbol; +export declare const AUTO_MERGED: unique symbol; +export declare const NOT_CONFLICTED: unique symbol; +export declare const MISSING_OR_ERROR: unique symbol; +export declare const LEAVE_TO_SUBSEQUENT: unique symbol; +export declare const TIME_ARGUMENT_INFINITY: unique symbol; +export declare const BASE_IS_NEW: unique symbol; +export declare const TARGET_IS_NEW: unique symbol; +export declare const EVEN: unique symbol; diff --git a/_types/lib/src/common/models/shared.definition.configNames.d.ts b/_types/lib/src/common/models/shared.definition.configNames.d.ts new file mode 100644 index 0000000..313fcfb --- /dev/null +++ b/_types/lib/src/common/models/shared.definition.configNames.d.ts @@ -0,0 +1,36 @@ +import type { ObsidianLiveSyncSettings } from "./setting.type"; +export declare const LEVEL_ADVANCED = "ADVANCED"; +export declare const LEVEL_POWER_USER = "POWER_USER"; +export declare const LEVEL_EDGE_CASE = "EDGE_CASE"; +export type ConfigLevel = "" | "ADVANCED" | "POWER_USER" | "EDGE_CASE"; +export type ConfigurationItem = { + name: string; + desc?: string; + placeHolder?: string; + status?: "BETA" | "ALPHA" | "EXPERIMENTAL"; + obsolete?: boolean; + level?: ConfigLevel; + isHidden?: boolean; + isAdvanced?: boolean; +}; +export declare const configurationNames: Partial>; +/** + * Get human readable Configuration stability + * @param status + * @returns + */ +export declare function statusDisplay(status?: string): string; +/** + * Get human readable configuration name. + * @param key configuration key + * @param alt + * @returns + */ +export declare function confName(key: keyof ObsidianLiveSyncSettings, alt?: string): string; +/** + * Get human readable configuration description. + * @param key configuration key + * @param alt + * @returns + */ +export declare function confDesc(key: keyof ObsidianLiveSyncSettings, alt?: string): string | undefined; diff --git a/_types/lib/src/common/models/shared.definition.d.ts b/_types/lib/src/common/models/shared.definition.d.ts new file mode 100644 index 0000000..2aff4a9 --- /dev/null +++ b/_types/lib/src/common/models/shared.definition.d.ts @@ -0,0 +1,22 @@ +export declare const DatabaseConnectingStatuses: { + readonly STARTED: "STARTED"; + readonly NOT_CONNECTED: "NOT_CONNECTED"; + readonly PAUSED: "PAUSED"; + readonly CONNECTED: "CONNECTED"; + readonly COMPLETED: "COMPLETED"; + readonly CLOSED: "CLOSED"; + readonly ERRORED: "ERRORED"; + readonly JOURNAL_SEND: "JOURNAL_SEND"; + readonly JOURNAL_RECEIVE: "JOURNAL_RECEIVE"; +}; +export type DatabaseConnectingStatus = (typeof DatabaseConnectingStatuses)[keyof typeof DatabaseConnectingStatuses]; +export type ReplicationStatics = { + sent: number; + arrived: number; + maxPullSeq: number; + maxPushSeq: number; + lastSyncPullSeq: number; + lastSyncPushSeq: number; + syncStatus: DatabaseConnectingStatus; +}; +export declare const DEFAULT_REPLICATION_STATICS: ReplicationStatics; diff --git a/_types/lib/src/common/models/shared.type.util.d.ts b/_types/lib/src/common/models/shared.type.util.d.ts new file mode 100644 index 0000000..fab7840 --- /dev/null +++ b/_types/lib/src/common/models/shared.type.util.d.ts @@ -0,0 +1,8 @@ +import type { TaggedType } from "octagonal-wheels/common/types"; +export type { TaggedType }; +export type CustomRegExpSource = TaggedType; +export type CustomRegExpSourceList = TaggedType; +export type ParsedCustomRegExp = [isInverted: boolean, pattern: string]; +export type Prettify = { + [K in keyof T]: T[K]; +} & {}; diff --git a/_types/lib/src/common/models/sync.definition.d.ts b/_types/lib/src/common/models/sync.definition.d.ts new file mode 100644 index 0000000..fd3cfb0 --- /dev/null +++ b/_types/lib/src/common/models/sync.definition.d.ts @@ -0,0 +1,18 @@ +import { EntryTypes } from "./db.const"; +import type { DatabaseEntry, DocumentID } from "./db.type"; +export declare const ProtocolVersions: { + readonly UNSET: undefined; + readonly LEGACY: 1; + readonly ADVANCED_E2EE: 2; +}; +export type ProtocolVersion = (typeof ProtocolVersions)[keyof typeof ProtocolVersions]; +export declare const DOCID_SYNC_PARAMETERS: DocumentID; +export declare const DOCID_JOURNAL_SYNC_PARAMETERS: DocumentID; +export interface SyncParameters extends DatabaseEntry { + _id: typeof DOCID_SYNC_PARAMETERS; + _rev?: string; + type: (typeof EntryTypes)["SYNC_PARAMETERS"]; + protocolVersion: ProtocolVersion; + pbkdf2salt: string; +} +export declare const DEFAULT_SYNC_PARAMETERS: SyncParameters; diff --git a/_types/lib/src/common/models/tweak.definition.d.ts b/_types/lib/src/common/models/tweak.definition.d.ts new file mode 100644 index 0000000..7620c1a --- /dev/null +++ b/_types/lib/src/common/models/tweak.definition.d.ts @@ -0,0 +1,190 @@ +import type { ObsidianLiveSyncSettings } from "./setting.type"; +export declare const TweakValuesShouldMatchedTemplate: Partial; +type TweakKeys = keyof TweakValues; +export declare const IncompatibleChanges: TweakKeys[]; +export declare const CompatibleButLossyChanges: TweakKeys[]; +type IncompatibleRecommendationPatterns = { + key: T; + isRecommendation?: boolean; +} & ({ + from: TweakValues[T]; + to: TweakValues[T]; +} | { + from: TweakValues[T]; +} | { + to: TweakValues[T]; +}); +export declare const IncompatibleChangesInSpecificPattern: IncompatibleRecommendationPatterns[]; +export declare const TweakValuesRecommendedTemplate: Partial; +export declare const TweakValuesDefault: Partial; +export declare const TweakValuesTemplate: { + tweakModified: number; + liveSync?: boolean | undefined; + syncOnSave?: boolean | undefined; + syncOnStart?: boolean | undefined; + syncOnFileOpen?: boolean | undefined; + syncOnEditorSave?: boolean | undefined; + syncMinimumInterval?: number | undefined; + showVerboseLog?: boolean | undefined; + lessInformationInLog?: boolean | undefined; + showLongerLogInsideEditor?: boolean | undefined; + showStatusOnEditor?: boolean | undefined; + showStatusOnStatusbar?: boolean | undefined; + showOnlyIconsOnEditor?: boolean | undefined; + hideFileWarningNotice?: boolean | undefined; + networkWarningStyle?: "" | "icon" | "hidden" | undefined; + displayLanguage?: import("../rosetta").I18N_LANGS | undefined; + trashInsteadDelete?: boolean | undefined; + doNotDeleteFolder?: boolean | undefined; + batchSave?: boolean | undefined; + batchSaveMinimumDelay?: number | undefined; + batchSaveMaximumDelay?: number | undefined; + syncMaxSizeInMB?: number | undefined; + useIgnoreFiles?: boolean | undefined; + ignoreFiles?: string | undefined; + processSizeMismatchedFiles?: boolean | undefined; + syncOnlyRegEx?: import("./shared.type.util").CustomRegExpSourceList<"|[]|"> | undefined; + syncIgnoreRegEx?: import("./shared.type.util").CustomRegExpSourceList<"|[]|"> | undefined; + syncAfterMerge?: boolean | undefined; + resolveConflictsByNewerFile?: boolean | undefined; + writeDocumentsIfConflicted?: boolean | undefined; + disableMarkdownAutoMerge?: boolean | undefined; + configPassphraseStore?: import("./setting.type").ConfigPassphraseStore | undefined; + encryptedPassphrase?: string | undefined; + encryptedCouchDBConnection?: string | undefined; + periodicReplication?: boolean | undefined; + periodicReplicationInterval?: number | undefined; + syncInternalFiles?: boolean | undefined; + syncInternalFilesBeforeReplication?: boolean | undefined; + syncInternalFilesInterval?: number | undefined; + syncInternalFilesIgnorePatterns?: import("./shared.type.util").CustomRegExpSourceList<","> | undefined; + syncInternalFilesTargetPatterns?: import("./shared.type.util").CustomRegExpSourceList<","> | undefined; + watchInternalFileChanges?: boolean | undefined; + suppressNotifyHiddenFilesChange?: boolean | undefined; + syncInternalFileOverwritePatterns?: import("./shared.type.util").CustomRegExpSourceList<","> | undefined; + usePluginSync?: boolean | undefined; + usePluginSettings?: boolean | undefined; + showOwnPlugins?: boolean | undefined; + autoSweepPlugins?: boolean | undefined; + autoSweepPluginsPeriodic?: boolean | undefined; + notifyPluginOrSettingUpdated?: boolean | undefined; + deviceAndVaultName?: string | undefined; + usePluginSyncV2?: boolean | undefined; + usePluginEtc?: boolean | undefined; + pluginSyncExtendedSetting?: Record | undefined; + useAdvancedMode?: boolean | undefined; + usePowerUserMode?: boolean | undefined; + useEdgeCaseMode?: boolean | undefined; + notifyThresholdOfRemoteStorageSize?: number | undefined; + disableWorkerForGeneratingChunks?: boolean | undefined; + processSmallFilesInUIThread?: boolean | undefined; + savingDelay?: number | undefined; + gcDelay?: number | undefined; + skipOlderFilesOnSync?: boolean | undefined; + useIndexedDBAdapter?: boolean | undefined; + enableDebugTools?: boolean | undefined; + writeLogToTheFile?: boolean | undefined; + settingSyncFile?: string | undefined; + writeCredentialsForSettingSync?: boolean | undefined; + notifyAllSettingSyncFile?: boolean | undefined; + suspendFileWatching?: boolean | undefined; + suspendParseReplicationResult?: boolean | undefined; + doNotSuspendOnFetching?: boolean | undefined; + maxMTimeForReflectEvents?: number | undefined; + versionUpFlash?: string | undefined; + settingVersion?: number | undefined; + isConfigured?: boolean; + lastReadUpdates?: number | undefined; + doctorProcessedVersion?: string | undefined; + remoteConfigurations?: Record | undefined; + activeConfigurationId?: string | undefined; + P2P_ActiveRemoteConfigurationId?: string | undefined; + couchDB_URI?: string | undefined; + couchDB_USER?: string | undefined; + couchDB_PASSWORD?: string | undefined; + couchDB_DBNAME?: string | undefined; + couchDB_CustomHeaders?: string | undefined; + useJWT?: boolean | undefined; + jwtAlgorithm?: import("./auth.type").JWTAlgorithm | undefined; + jwtKey?: string | undefined; + jwtKid?: string | undefined; + jwtSub?: string | undefined; + jwtExpDuration?: number | undefined; + useRequestAPI?: boolean | undefined; + accessKey?: string | undefined; + secretKey?: string | undefined; + bucket?: string | undefined; + region?: string | undefined; + endpoint?: string | undefined; + useCustomRequestHandler?: boolean | undefined; + bucketCustomHeaders?: string | undefined; + bucketPrefix?: string | undefined; + forcePathStyle?: boolean | undefined; + remoteType?: import("./setting.type").RemoteType | undefined; + encrypt?: boolean | undefined; + passphrase?: string | undefined; + usePathObfuscation?: boolean | undefined; + E2EEAlgorithm?: import("./setting.type").E2EEAlgorithm | undefined; + hashAlg?: import("./setting.type").HashAlgorithm | undefined; + minimumChunkSize?: number | undefined; + customChunkSize?: number | undefined; + longLineThreshold?: number | undefined; + useSegmenter?: boolean | undefined; + enableChunkSplitterV2?: boolean | undefined; + doNotUseFixedRevisionForChunks?: boolean | undefined; + chunkSplitterVersion?: import("./setting.type").ChunkSplitterVersion | undefined; + useEden?: boolean | undefined; + maxChunksInEden?: number | undefined; + maxTotalLengthInEden?: number | undefined; + maxAgeInEden?: number | undefined; + checkIntegrityOnSave?: boolean | undefined; + useHistory?: boolean | undefined; + disableRequestURI?: boolean | undefined; + sendChunksBulk?: boolean | undefined; + sendChunksBulkMaxSize?: number | undefined; + useDynamicIterationCount?: boolean | undefined; + doNotPaceReplication?: boolean | undefined; + readChunksOnline?: boolean | undefined; + useOnlyLocalChunk?: boolean | undefined; + concurrencyOfReadChunksOnline?: number | undefined; + minimumIntervalOfReadChunksOnline?: number | undefined; + enableCompression?: boolean | undefined; + batch_size?: number | undefined; + batches_limit?: number | undefined; + ignoreVersionCheck?: boolean | undefined; + disableCheckingConfigMismatch?: boolean | undefined; + autoAcceptCompatibleTweak?: boolean | undefined; + hashCacheMaxCount?: number | undefined; + hashCacheMaxAmount?: number | undefined; + permitEmptyPassphrase?: boolean | undefined; + handleFilenameCaseSensitive?: boolean | undefined; + checkConflictOnlyOnOpen?: boolean | undefined; + showMergeDialogOnlyOnActive?: boolean | undefined; + additionalSuffixOfDatabaseName?: string | undefined; + useTimeouts?: boolean | undefined; + deleteMetadataOfDeletedFiles?: boolean | undefined; + automaticallyDeleteMetadataOfDeletedFiles?: number | undefined; + P2P_AutoAccepting?: import("./setting.type").AutoAccepting | undefined; + P2P_AutoSyncPeers?: string | undefined; + P2P_AutoWatchPeers?: string | undefined; + P2P_SyncOnReplication?: string | undefined; + P2P_RebuildFrom?: string | undefined; + P2P_AutoAcceptingPeers?: string | undefined; + P2P_AutoDenyingPeers?: string | undefined; + P2P_IsHeadless?: boolean; + P2P_Enabled?: boolean | undefined; + P2P_relays?: string | undefined; + P2P_roomID?: string | undefined; + P2P_passphrase?: string | undefined; + P2P_AppID?: string | undefined; + P2P_AutoStart?: boolean | undefined; + P2P_AutoBroadcast?: boolean | undefined; + P2P_DevicePeerName?: string; + P2P_turnServers?: string | undefined; + P2P_turnUsername?: string | undefined; + P2P_turnCredential?: string | undefined; + P2P_useDiagRTC?: boolean; +}; +export type TweakValues = Partial; +export declare const DEVICE_ID_PREFERRED = "PREFERRED"; +export {}; diff --git a/_types/lib/src/common/rosetta.d.ts b/_types/lib/src/common/rosetta.d.ts new file mode 100644 index 0000000..682cd5c --- /dev/null +++ b/_types/lib/src/common/rosetta.d.ts @@ -0,0 +1,42 @@ +/** +# Rosetta stone +- To localise messages to your language, please write a translation to this file and submit a PR. +- Please order languages in alphabetic order, if you write multiple items. + +## Notice to ensure that your favours are not wasted. + +If you plan to utilise machine translation engines to contribute translated resources, +please ensure the engine's terms of service are compatible with our project's license. +Your diligence in this matter helps maintain compliance and avoid potential licensing issues. +Thank you for your consideration. + +Usually, our projects (Self-hosted LiveSync and its families) are licensed under MIT License. +To see details, please refer to the LICENSES file on each repository. + +## How to internationalise untranslated items? +1. Change the message literal to use `$msg` + "Could not parse YAML" -> $msg('anyKey') +2. Create `ls-debug` folder under the `.obsidian` folder of your vault. +3. Run Self-hosted LiveSync in dev mode (npm run dev). +4. You will get the `missing-translation-YYYY-MM-DD.jsonl` under `ls-debug`. Please copy and paste inside `allMessages` and write the translations. +5. Send me the PR! +*/ +declare const LANG_DE = "de"; +declare const LANG_ES = "es"; +declare const LANG_FR = "fr"; +declare const LANG_HE = "he"; +declare const LANG_JA = "ja"; +declare const LANG_RU = "ru"; +declare const LANG_ZH = "zh"; +declare const LANG_KO = "ko"; +declare const LANG_ZH_TW = "zh-tw"; +declare const LANG_DEF = "def"; +export declare const SUPPORTED_I18N_LANGS: string[]; +export type I18N_LANGS = typeof LANG_DEF | typeof LANG_DE | typeof LANG_ES | typeof LANG_FR | typeof LANG_HE | typeof LANG_JA | typeof LANG_KO | typeof LANG_RU | typeof LANG_ZH | typeof LANG_ZH_TW | ""; +export type MESSAGE = { + [key in I18N_LANGS]?: string; +}; +import { type MessageKeys } from "./messages/combinedMessages.dev"; +export declare function expandKeywords, U extends Record>(message: T, lang: I18N_LANGS, recurseLimit?: number): T; +export type AllMessageKeys = MessageKeys; +export {}; diff --git a/_types/lib/src/common/settingConstants.d.ts b/_types/lib/src/common/settingConstants.d.ts new file mode 100644 index 0000000..166739a --- /dev/null +++ b/_types/lib/src/common/settingConstants.d.ts @@ -0,0 +1,215 @@ +import type { ConfigurationItem } from "@lib/common/models/shared.definition.configNames"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +type ExtractPropertiesByType = { + [K in keyof T as T[K] extends U ? K : never]: T[K] extends U ? K : never; +}; +export type FilterStringKeys = keyof ExtractPropertiesByType; +export type FilterBooleanKeys = keyof ExtractPropertiesByType; +export type FilterNumberKeys = keyof ExtractPropertiesByType; +import type { FilePath, FilePathWithPrefixLC, FilePathWithPrefix, DocumentID } from "./models/db.type.ts"; +export type { FilePath, FilePathWithPrefixLC, FilePathWithPrefix, DocumentID }; +/** + * Self-hosted LiveSync settings pane items. + */ +export type OnDialogSettings = { + configPassphrase: string; + preset: "" | "PERIODIC" | "LIVESYNC" | "DISABLE"; + syncMode: "ONEVENTS" | "PERIODIC" | "LIVESYNC"; + dummy: number; + deviceAndVaultName: string; +}; +/** + * Default settings for the OnDialogSettings. + * Not used for the common library, but used for the Obsidian plugin. + */ +export declare const OnDialogSettingsDefault: OnDialogSettings; +export declare const AllSettingDefault: { + configPassphrase: string; + preset: "" | "PERIODIC" | "LIVESYNC" | "DISABLE"; + syncMode: "ONEVENTS" | "PERIODIC" | "LIVESYNC"; + dummy: number; + deviceAndVaultName: string; + liveSync: boolean; + syncOnSave: boolean; + syncOnStart: boolean; + syncOnFileOpen: boolean; + syncOnEditorSave: boolean; + syncMinimumInterval: number; + showVerboseLog: boolean; + lessInformationInLog: boolean; + showLongerLogInsideEditor: boolean; + showStatusOnEditor: boolean; + showStatusOnStatusbar: boolean; + showOnlyIconsOnEditor: boolean; + hideFileWarningNotice: boolean; + networkWarningStyle: "" | "icon" | "hidden"; + displayLanguage: import("./rosetta.ts").I18N_LANGS; + trashInsteadDelete: boolean; + doNotDeleteFolder: boolean; + batchSave: boolean; + batchSaveMinimumDelay: number; + batchSaveMaximumDelay: number; + syncMaxSizeInMB: number; + useIgnoreFiles: boolean; + ignoreFiles: string; + processSizeMismatchedFiles: boolean; + syncOnlyRegEx: import("./types.ts").CustomRegExpSourceList<"|[]|">; + syncIgnoreRegEx: import("./types.ts").CustomRegExpSourceList<"|[]|">; + syncAfterMerge: boolean; + resolveConflictsByNewerFile: boolean; + writeDocumentsIfConflicted: boolean; + disableMarkdownAutoMerge: boolean; + configPassphraseStore: import("@lib/common/models/setting.type").ConfigPassphraseStore; + encryptedPassphrase: string; + encryptedCouchDBConnection: string; + periodicReplication: boolean; + periodicReplicationInterval: number; + syncInternalFiles: boolean; + syncInternalFilesBeforeReplication: boolean; + syncInternalFilesInterval: number; + syncInternalFilesIgnorePatterns: import("./types.ts").CustomRegExpSourceList<",">; + syncInternalFilesTargetPatterns: import("./types.ts").CustomRegExpSourceList<",">; + watchInternalFileChanges: boolean; + suppressNotifyHiddenFilesChange: boolean; + syncInternalFileOverwritePatterns: import("./types.ts").CustomRegExpSourceList<",">; + usePluginSync: boolean; + usePluginSettings: boolean; + showOwnPlugins: boolean; + autoSweepPlugins: boolean; + autoSweepPluginsPeriodic: boolean; + notifyPluginOrSettingUpdated: boolean; + usePluginSyncV2: boolean; + usePluginEtc: boolean; + pluginSyncExtendedSetting: Record; + useAdvancedMode: boolean; + usePowerUserMode: boolean; + useEdgeCaseMode: boolean; + notifyThresholdOfRemoteStorageSize: number; + disableWorkerForGeneratingChunks: boolean; + processSmallFilesInUIThread: boolean; + savingDelay: number; + gcDelay: number; + skipOlderFilesOnSync: boolean; + useIndexedDBAdapter: boolean; + enableDebugTools: boolean; + writeLogToTheFile: boolean; + settingSyncFile: string; + writeCredentialsForSettingSync: boolean; + notifyAllSettingSyncFile: boolean; + suspendFileWatching: boolean; + suspendParseReplicationResult: boolean; + doNotSuspendOnFetching: boolean; + maxMTimeForReflectEvents: number; + versionUpFlash: string; + settingVersion: number; + isConfigured?: boolean; + lastReadUpdates: number; + doctorProcessedVersion: string; + remoteConfigurations: Record; + activeConfigurationId: string; + P2P_ActiveRemoteConfigurationId: string; + couchDB_URI: string; + couchDB_USER: string; + couchDB_PASSWORD: string; + couchDB_DBNAME: string; + couchDB_CustomHeaders: string; + useJWT: boolean; + jwtAlgorithm: import("./models/auth.type.ts").JWTAlgorithm; + jwtKey: string; + jwtKid: string; + jwtSub: string; + jwtExpDuration: number; + useRequestAPI: boolean; + accessKey: string; + secretKey: string; + bucket: string; + region: string; + endpoint: string; + useCustomRequestHandler: boolean; + bucketCustomHeaders: string; + bucketPrefix: string; + forcePathStyle: boolean; + remoteType: import("@lib/common/models/setting.type").RemoteType; + encrypt: boolean; + passphrase: string; + usePathObfuscation: boolean; + E2EEAlgorithm: import("@lib/common/models/setting.type").E2EEAlgorithm; + hashAlg: import("@lib/common/models/setting.type").HashAlgorithm; + minimumChunkSize: number; + customChunkSize: number; + longLineThreshold: number; + useSegmenter: boolean; + enableChunkSplitterV2: boolean; + doNotUseFixedRevisionForChunks: boolean; + chunkSplitterVersion: import("@lib/common/models/setting.type").ChunkSplitterVersion; + useEden: boolean; + maxChunksInEden: number; + maxTotalLengthInEden: number; + maxAgeInEden: number; + tweakModified: number | undefined; + checkIntegrityOnSave: boolean; + useHistory: boolean; + disableRequestURI: boolean; + sendChunksBulk: boolean; + sendChunksBulkMaxSize: number; + useDynamicIterationCount: boolean; + doNotPaceReplication: boolean; + readChunksOnline: boolean; + useOnlyLocalChunk: boolean; + concurrencyOfReadChunksOnline: number; + minimumIntervalOfReadChunksOnline: number; + enableCompression: boolean; + batch_size: number; + batches_limit: number; + ignoreVersionCheck: boolean; + disableCheckingConfigMismatch: boolean; + autoAcceptCompatibleTweak: boolean | undefined; + hashCacheMaxCount: number; + hashCacheMaxAmount: number; + permitEmptyPassphrase: boolean; + handleFilenameCaseSensitive: boolean; + checkConflictOnlyOnOpen: boolean; + showMergeDialogOnlyOnActive: boolean; + additionalSuffixOfDatabaseName: string | undefined; + useTimeouts: boolean; + deleteMetadataOfDeletedFiles: boolean; + automaticallyDeleteMetadataOfDeletedFiles: number; + P2P_AutoAccepting: import("@lib/common/models/setting.type").AutoAccepting; + P2P_AutoSyncPeers: string; + P2P_AutoWatchPeers: string; + P2P_SyncOnReplication: string; + P2P_RebuildFrom: string; + P2P_AutoAcceptingPeers: string; + P2P_AutoDenyingPeers: string; + P2P_IsHeadless?: boolean; + P2P_Enabled: boolean; + P2P_relays: string; + P2P_roomID: string; + P2P_passphrase: string; + P2P_AppID: string; + P2P_AutoStart: boolean; + P2P_AutoBroadcast: boolean; + P2P_DevicePeerName?: string; + P2P_turnServers: string; + P2P_turnUsername: string; + P2P_turnCredential: string; + P2P_useDiagRTC?: boolean; +}; +export type AllSettings = ObsidianLiveSyncSettings & OnDialogSettings; +export type AllStringItemKey = FilterStringKeys; +export type AllNumericItemKey = FilterNumberKeys; +export type AllBooleanItemKey = FilterBooleanKeys; +export type AllSettingItemKey = AllStringItemKey | AllNumericItemKey | AllBooleanItemKey; +export type ValueOf = T extends AllStringItemKey ? string : T extends AllNumericItemKey ? number : T extends AllBooleanItemKey ? boolean : AllSettings[T]; +export declare const SettingInformation: Partial>; +export declare function getConfig(key: AllSettingItemKey): false | { + name: string; + desc?: string; + placeHolder?: string; + status?: "BETA" | "ALPHA" | "EXPERIMENTAL"; + obsolete?: boolean; + level?: import("@lib/common/models/shared.definition.configNames").ConfigLevel; + isHidden?: boolean; + isAdvanced?: boolean; +}; +export declare function getConfName(key: AllSettingItemKey): string; diff --git a/_types/lib/src/common/typeUtils.d.ts b/_types/lib/src/common/typeUtils.d.ts new file mode 100644 index 0000000..a8e2471 --- /dev/null +++ b/_types/lib/src/common/typeUtils.d.ts @@ -0,0 +1,17 @@ +import type { DocumentID, FilePath, FilePathWithPrefix } from "./models/db.type"; +import type { UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +/** + * returns is internal chunk of file + * @param id ID + * @returns + */ +export declare function isInternalMetadata(id: FilePath | FilePathWithPrefix | DocumentID): boolean; +export declare function isInternalFile(file: UXFileInfoStub | string | FilePathWithPrefix): boolean; +export declare function stripInternalMetadataPrefix(id: T): T; +export declare function id2InternalMetadataId(id: DocumentID): DocumentID; +export declare function isChunk(str: string): boolean; +export declare function isPluginMetadata(str: string): boolean; +export declare function isCustomisationSyncMetadata(str: string): boolean; +export declare function getPathFromUXFileInfo(file: UXFileInfoStub | string | FilePathWithPrefix): FilePathWithPrefix; +export declare function getStoragePathFromUXFileInfo(file: UXFileInfoStub | string | FilePathWithPrefix): FilePath; +export declare function getDatabasePathFromUXFileInfo(file: UXFileInfoStub | string | FilePathWithPrefix): FilePathWithPrefix; diff --git a/_types/lib/src/common/types.d.ts b/_types/lib/src/common/types.d.ts new file mode 100644 index 0000000..9ef44a9 --- /dev/null +++ b/_types/lib/src/common/types.d.ts @@ -0,0 +1,107 @@ +export type { TaggedType } from "./models/shared.type.util.ts"; +export { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_URGENT, LOG_LEVEL_VERBOSE, } from "octagonal-wheels/common/logger"; +export type { LOG_LEVEL } from "octagonal-wheels/common/logger"; +import { RESULT_NOT_FOUND, RESULT_TIMED_OUT } from "octagonal-wheels/common/const"; +import type { Credential } from "./models/auth.type.ts"; +import type { AnyEntry, ChunkVersionRange, DatabaseEntry, EdenChunk, EntryBase, EntryChunkPack, EntryHasPath, EntryLeaf, EntryType, EntryTypeNotes, EntryTypeNotesWithLegacy, EntryVersionInfo, EntryWithEden, InternalFileEntry, LoadedEntry, MetaEntry, NewEntry, NoteEntry, PlainEntry, SavingEntry, SyncInfo } from "./models/db.type.ts"; +import { ChunkTypes, EntryTypes, MILESTONE_DOCID, NODEINFO_DOCID, NoteTypes, SYNCINFO_ID, VERSIONING_DOCID } from "./models/db.const.ts"; +import { AUTO_MERGED, CANCELLED, LEAVE_TO_SUBSEQUENT, MISSING_OR_ERROR, NOT_CONFLICTED, TIME_ARGUMENT_INFINITY } from "./models/shared.const.symbols.ts"; +import { IDPrefixes, LEAF_WAIT_ONLY_REMOTE, LEAF_WAIT_TIMEOUT, LEAF_WAIT_TIMEOUT_SEQUENTIAL_REPLICATOR, MAX_DOC_SIZE, MAX_DOC_SIZE_BIN, PREFIX_CHUNK, PREFIX_ENCRYPTED_CHUNK, PREFIX_OBFUSCATED, RECENT_MODIFIED_DOCS_QTY, REPLICATION_BUSY_TIMEOUT, SALT_OF_ID, SALT_OF_PASSPHRASE, SEED_MURMURHASH, VER } from "./models/shared.const.behabiour.ts"; +import { AutoAccepting, type BucketSyncSetting, type ChunkSplitterVersion, type ConfigPassphraseStore, type CouchDBConnection, type E2EEAlgorithm, type EncryptionSettings, type HashAlgorithm, type HasSettings, type LocalDBSettings, type ObsidianLiveSyncSettings, type P2PConnectionInfo, type P2PSyncSetting, type PluginSyncSettingEntry, type RemoteDBSettings, type RemoteType, type RemoteTypeSettings, type SYNC_MODE } from "./models/setting.type.ts"; +import { ChunkAlgorithmNames, ChunkAlgorithms, CURRENT_SETTING_VERSION, E2EEAlgorithmNames, E2EEAlgorithms, HashAlgorithms, REMOTE_COUCHDB, REMOTE_MINIO, REMOTE_P2P, RemoteTypes, SETTING_VERSION_INITIAL, SETTING_VERSION_SUPPORT_CASE_INSENSITIVE, MODE_AUTOMATIC, MODE_PAUSED, MODE_SELECTIVE, MODE_SHINY } from "./models/setting.const.ts"; +import { PREFERRED_BASE, PREFERRED_JOURNAL_SYNC, PREFERRED_SETTING_CLOUDANT, PREFERRED_SETTING_SELF_HOSTED } from "./models/setting.const.preferred.ts"; +import { P2P_DEFAULT_SETTINGS, DEFAULT_SETTINGS } from "./models/setting.const.defaults.ts"; +import { KeyIndexOfSettings } from "./models/setting.const.qr.ts"; +import type { DeviceInfo, EntryBody, EntryDoc, EntryDocResponse, EntryMilestoneInfo, EntryNodeInfo, NodeData, NodeKey } from "./models/db.definition.ts"; +import { isMetaEntry } from "./models/db.definition.ts"; +import type { CouchDBCredentials, BasicCredentials, JWTCredentials, JWTHeader, JWTPayload, JWTParams, PreparedJWT } from "./models/auth.type.ts"; +import type { CacheData, FileEventArgs, FileEventItem, FileEventType, UXAbstractInfoStub, UXDataWriteOptions, UXFileInfo, UXFileInfoStub, UXFolderInfo, UXInternalFileInfoStub, UXStat } from "./models/fileaccess.type.ts"; +import { SETTING_KEY_P2P_DEVICE_NAME, configURIBase, configURIBaseQR, SuffixDatabaseName, ExtraSuffixIndexedDB } from "./models/shared.const.ts"; +import { configurationNames, LEVEL_ADVANCED, LEVEL_POWER_USER, LEVEL_EDGE_CASE, type ConfigLevel, type ConfigurationItem, statusDisplay, confName, confDesc } from "./models/shared.definition.configNames.ts"; +import type { CustomRegExpSource, CustomRegExpSourceList, ParsedCustomRegExp, Prettify } from "./models/shared.type.util.ts"; +import { ProtocolVersions, type ProtocolVersion, DOCID_SYNC_PARAMETERS, DOCID_JOURNAL_SYNC_PARAMETERS, type SyncParameters, DEFAULT_SYNC_PARAMETERS } from "./models/sync.definition.ts"; +import { TweakValuesShouldMatchedTemplate, IncompatibleChanges, CompatibleButLossyChanges, IncompatibleChangesInSpecificPattern, TweakValuesRecommendedTemplate, TweakValuesDefault, TweakValuesTemplate, type TweakValues, DEVICE_ID_PREFERRED } from "./models/tweak.definition.ts"; +import type { diff_result_leaf, dmp_result, diff_result, DIFF_CHECK_RESULT_AUTO, diff_check_result } from "./models/diff.definition.ts"; +import { PREFIXMD_LOGFILE, PREFIXMD_LOGFILE_UC, FlagFilesOriginal, FlagFilesHumanReadable, FLAGMD_REDFLAG, FLAGMD_REDFLAG2, FLAGMD_REDFLAG2_HR, FLAGMD_REDFLAG3, FLAGMD_REDFLAG3_HR } from "./models/redflag.const.ts"; +import { DatabaseConnectingStatuses, type DatabaseConnectingStatus } from "./models/shared.definition.ts"; +export { RESULT_NOT_FOUND, RESULT_TIMED_OUT }; +export type { FilePath, FilePathWithPrefixLC, FilePathWithPrefix, DocumentID } from "./models/db.type.ts"; +export { MAX_DOC_SIZE, MAX_DOC_SIZE_BIN, VER, RECENT_MODIFIED_DOCS_QTY, LEAF_WAIT_TIMEOUT, LEAF_WAIT_ONLY_REMOTE, LEAF_WAIT_TIMEOUT_SEQUENTIAL_REPLICATOR, REPLICATION_BUSY_TIMEOUT, CANCELLED, AUTO_MERGED, NOT_CONFLICTED, MISSING_OR_ERROR, LEAVE_TO_SUBSEQUENT, TIME_ARGUMENT_INFINITY, VERSIONING_DOCID, MILESTONE_DOCID, NODEINFO_DOCID, }; +export { type CouchDBConnection }; +export type { ConfigPassphraseStore }; +export { MODE_SELECTIVE, MODE_AUTOMATIC, MODE_PAUSED, MODE_SHINY, type SYNC_MODE }; +export { type PluginSyncSettingEntry }; +export { SETTING_VERSION_INITIAL, SETTING_VERSION_SUPPORT_CASE_INSENSITIVE, CURRENT_SETTING_VERSION }; +export type { BucketSyncSetting, LocalDBSettings }; +export { RemoteTypes, REMOTE_COUCHDB, REMOTE_MINIO, REMOTE_P2P, type RemoteType, AutoAccepting }; +export type { P2PConnectionInfo, P2PSyncSetting }; +export { P2P_DEFAULT_SETTINGS }; +export type { RemoteTypeSettings }; +export { E2EEAlgorithmNames, E2EEAlgorithms, type E2EEAlgorithm }; +export type { EncryptionSettings }; +export { HashAlgorithms, type HashAlgorithm, ChunkAlgorithmNames, ChunkAlgorithms, type ChunkSplitterVersion }; +export type { RemoteDBSettings }; +export type { ObsidianLiveSyncSettings }; +export { DEFAULT_SETTINGS }; +export { KeyIndexOfSettings }; +export { type HasSettings }; +export { PREFERRED_BASE, PREFERRED_SETTING_CLOUDANT, PREFERRED_SETTING_SELF_HOSTED, PREFERRED_JOURNAL_SYNC }; +export { EntryTypes, NoteTypes, ChunkTypes, type EntryType, type EntryTypeNotes, type EntryTypeNotesWithLegacy, type DatabaseEntry, type EntryBase, type EdenChunk, type EntryWithEden, type NoteEntry, type NewEntry, type PlainEntry, type InternalFileEntry, type AnyEntry, type LoadedEntry, type SavingEntry, type MetaEntry, isMetaEntry, type EntryLeaf, type EntryChunkPack, type EntryVersionInfo, type EntryHasPath, }; +export type { ChunkVersionRange }; +export { TweakValuesShouldMatchedTemplate }; +export { IncompatibleChanges }; +export { CompatibleButLossyChanges }; +export { IncompatibleChangesInSpecificPattern }; +export { TweakValuesRecommendedTemplate }; +export { TweakValuesDefault }; +export { configurationNames }; +export { LEVEL_ADVANCED }; +export { LEVEL_POWER_USER }; +export { LEVEL_EDGE_CASE }; +export type { ConfigLevel }; +export type { ConfigurationItem }; +export { statusDisplay }; +export { confName }; +export { confDesc }; +export { TweakValuesTemplate }; +export type { TweakValues }; +export { DEVICE_ID_PREFERRED }; +export type { NodeKey }; +export type { DeviceInfo }; +export type { NodeData }; +export type { EntryMilestoneInfo }; +export type { EntryNodeInfo }; +export type { EntryBody }; +export type { EntryDoc }; +export type { diff_result_leaf }; +export type { dmp_result }; +export type { diff_result }; +export type { DIFF_CHECK_RESULT_AUTO }; +export type { diff_check_result }; +export type { Credential }; +export type { EntryDocResponse }; +export { DatabaseConnectingStatuses }; +export type { DatabaseConnectingStatus }; +export { PREFIXMD_LOGFILE, PREFIXMD_LOGFILE_UC, FlagFilesOriginal, FlagFilesHumanReadable, FLAGMD_REDFLAG, FLAGMD_REDFLAG2, FLAGMD_REDFLAG2_HR, FLAGMD_REDFLAG3, FLAGMD_REDFLAG3_HR, }; +export { SYNCINFO_ID }; +export type { SyncInfo }; +export { SALT_OF_PASSPHRASE, SALT_OF_ID, SEED_MURMURHASH, IDPrefixes, PREFIX_OBFUSCATED, PREFIX_CHUNK, PREFIX_ENCRYPTED_CHUNK, }; +export type { UXStat, UXFileInfo, UXAbstractInfoStub, UXFileInfoStub, UXInternalFileInfoStub, UXFolderInfo, UXDataWriteOptions, CacheData, FileEventType, FileEventArgs, FileEventItem, }; +export type { Prettify }; +export type { CouchDBCredentials }; +export type { BasicCredentials }; +export type { JWTCredentials }; +export type { JWTHeader }; +export type { JWTPayload }; +export type { JWTParams }; +export type { PreparedJWT }; +export type { CustomRegExpSource }; +export type { CustomRegExpSourceList }; +export type { ParsedCustomRegExp }; +export { ProtocolVersions }; +export type { ProtocolVersion }; +export { DOCID_SYNC_PARAMETERS }; +export { DOCID_JOURNAL_SYNC_PARAMETERS }; +export type { SyncParameters }; +export { DEFAULT_SYNC_PARAMETERS }; +export { SETTING_KEY_P2P_DEVICE_NAME, configURIBase, configURIBaseQR, SuffixDatabaseName, ExtraSuffixIndexedDB }; diff --git a/_types/lib/src/common/utils.concurrency.d.ts b/_types/lib/src/common/utils.concurrency.d.ts new file mode 100644 index 0000000..5e33c36 --- /dev/null +++ b/_types/lib/src/common/utils.concurrency.d.ts @@ -0,0 +1,10 @@ +export declare function resolveWithIgnoreKnownError(p: Promise, def: T): Promise; +export declare const Parallels: (ps?: Set>) => { + add: (p: Promise) => Set>; + wait: (limit: number) => false | Promise; + all: () => Promise; +}; +export declare function allSettledWithConcurrencyLimit(processes: Promise[], limit: number): Promise; +export declare const globalConcurrencyController: import("octagonal-wheels/concurrency/semaphore_v2").SemaphoreObject; +export declare function wrapException(func: () => Promise>): Promise | Error>; +export declare function wrapByDefault(func: () => T, onError: (err: Error) => U): T | U; diff --git a/_types/lib/src/common/utils.d.ts b/_types/lib/src/common/utils.d.ts new file mode 100644 index 0000000..1d8ca25 --- /dev/null +++ b/_types/lib/src/common/utils.d.ts @@ -0,0 +1,25 @@ +import { replaceAll, replaceAllPairs } from "octagonal-wheels/string"; +export { replaceAll, replaceAllPairs }; +import { concatUInt8Array } from "octagonal-wheels/binary"; +export { concatUInt8Array }; +import { delay, fireAndForget } from "octagonal-wheels/promises"; +export { delay, fireAndForget }; +import { arrayToChunkedArray, unique } from "octagonal-wheels/collection"; +export { arrayToChunkedArray, unique }; +import { extractObject, isObjectDifferent } from "octagonal-wheels/object"; +export { extractObject, isObjectDifferent }; +import { sendValue, sendSignal, waitForSignal, waitForValue } from "octagonal-wheels/messagepassing/signal"; +export { sendValue, sendSignal, waitForSignal, waitForValue }; +import { throttle } from "octagonal-wheels/function"; +export { throttle }; +import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase"; +export type { SimpleStore }; +export { sizeToHumanReadable } from "octagonal-wheels/number"; +export * from "./utils.concurrency"; +export * from "./utils.timer"; +export * from "./utils.notations"; +export * from "./utils.database"; +export * from "./utils.regexp"; +export * from "./utils.settings"; +export * from "./utils.patch"; +export * from "./utils.misc"; diff --git a/_types/lib/src/common/utils.database.d.ts b/_types/lib/src/common/utils.database.d.ts new file mode 100644 index 0000000..e4e0cb3 --- /dev/null +++ b/_types/lib/src/common/utils.database.d.ts @@ -0,0 +1,23 @@ +import type { AnyEntry, DatabaseEntry, EntryLeaf, SyncInfo, LoadedEntry, SavingEntry, NewEntry, PlainEntry } from "@lib/common/models/db.type"; +import { BASE_IS_NEW, EVEN, TARGET_IS_NEW } from "./models/shared.const.symbols.ts"; +export declare function getDocData(doc: string | string[]): string; +export declare function getDocDataAsArray(doc: string | string[]): string[]; +export declare function getDocDataAsArrayBuffer(doc: string | string[] | ArrayBuffer): Uint8Array; +export declare function isTextBlob(blob: Blob): boolean; +export declare function createTextBlob(data: string | string[]): Blob; +export declare function createBinaryBlob(data: Uint8Array | ArrayBuffer): Blob; +export declare function createBlob(data: string | string[] | Uint8Array | ArrayBuffer | Blob): Blob; +export declare function isTextDocument(doc: LoadedEntry): boolean; +export declare function readAsBlob(doc: LoadedEntry): Blob; +export declare function readContent(doc: LoadedEntry): string | ArrayBuffer; +export declare function isDocContentSame(docA: string | string[] | Blob | ArrayBuffer, docB: string | string[] | Blob | ArrayBuffer): Promise; +export declare function isObfuscatedEntry(doc: DatabaseEntry): doc is AnyEntry; +export declare function isEncryptedChunkEntry(doc: DatabaseEntry): doc is EntryLeaf; +export declare function isSyncInfoEntry(doc: DatabaseEntry): doc is SyncInfo; +export declare function determineTypeFromBlob(data: Blob): "newnote" | "plain"; +export declare function determineType(path: string, data: string | string[] | Uint8Array | ArrayBuffer | Blob): "newnote" | "plain"; +export declare function isAnyNote(doc: DatabaseEntry): doc is NewEntry | PlainEntry; +export declare function isLoadedEntry(doc: DatabaseEntry): doc is LoadedEntry; +export declare function isDeletedEntry(doc: LoadedEntry): boolean; +export declare function createSavingEntryFromLoadedEntry(doc: LoadedEntry): SavingEntry; +export declare function compareMTime(baseMTime: number, targetMTime: number): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; diff --git a/_types/lib/src/common/utils.doc.d.ts b/_types/lib/src/common/utils.doc.d.ts new file mode 100644 index 0000000..51c59d8 --- /dev/null +++ b/_types/lib/src/common/utils.doc.d.ts @@ -0,0 +1,8 @@ +/** + * Checks if the error is effectively a 404 error from CouchDB or PouchDB. + * @param ex some error object, expected to be from CouchDB or PouchDB. + * @returns true if the error is a 404 not found error, false otherwise. + * @throws if the input is not an object or does not have a numeric "status" property. + */ +export declare function isNotFoundError(ex: unknown): boolean; +export declare function tryGetFilePath(entry: unknown): string | undefined; diff --git a/_types/lib/src/common/utils.misc.d.ts b/_types/lib/src/common/utils.misc.d.ts new file mode 100644 index 0000000..212ed81 --- /dev/null +++ b/_types/lib/src/common/utils.misc.d.ts @@ -0,0 +1,13 @@ +export declare function tryParseJSON(str: string, fallbackValue?: T): T | undefined; +export declare function parseHeaderValues(strHeader: string): Record; +export declare function memorizeFuncWithLRUCache(func: (key: T) => U): (key: T) => U | undefined; +/** + * + * @param exclusion return only not exclusion + * @returns + * + * ["something",false,"aaaaa"].filter(onlyNot(false)) => yields ["something","aaaaaa"]. but, as string[]. + */ +export declare function onlyNot(exclusion: B): (item: A | B) => item is Exclude; +export declare function isDirty(key: string, value: unknown): boolean; +export declare function setAllItems(set: Set, items: T[]): Set; diff --git a/_types/lib/src/common/utils.notations.d.ts b/_types/lib/src/common/utils.notations.d.ts new file mode 100644 index 0000000..7a5238b --- /dev/null +++ b/_types/lib/src/common/utils.notations.d.ts @@ -0,0 +1,6 @@ +export declare function escapeNewLineFromString(str: string): string; +export declare function unescapeNewLineFromString(str: string): string; +export declare function escapeMarkdownValue(value: T): T; +export declare function timeDeltaToHumanReadable(delta: number): string; +export declare function toRanges(sorted: number[]): string; +export declare function displayRev(rev: string): string; diff --git a/_types/lib/src/common/utils.object.d.ts b/_types/lib/src/common/utils.object.d.ts new file mode 100644 index 0000000..164552a --- /dev/null +++ b/_types/lib/src/common/utils.object.d.ts @@ -0,0 +1,2 @@ +export declare function asCopy(obj: T): T; +export declare function ensureError(error: unknown): Error; diff --git a/_types/lib/src/common/utils.patch.d.ts b/_types/lib/src/common/utils.patch.d.ts new file mode 100644 index 0000000..15edb25 --- /dev/null +++ b/_types/lib/src/common/utils.patch.d.ts @@ -0,0 +1,8 @@ +export declare function generatePatchObj(from: Record, to: Record): Record; +export declare function applyPatch(from: Record, patch: Record): Record; +export declare function mergeObject(objA: Record | [unknown], objB: Record | [unknown]): unknown[] | { + [k: string]: unknown; +}; +export declare function flattenObject(obj: Record, path?: string[]): [string, unknown][]; +export declare function isSensibleMargeApplicable(path: string): boolean; +export declare function isObjectMargeApplicable(path: string): boolean; diff --git a/_types/lib/src/common/utils.regexp.d.ts b/_types/lib/src/common/utils.regexp.d.ts new file mode 100644 index 0000000..3f43b3a --- /dev/null +++ b/_types/lib/src/common/utils.regexp.d.ts @@ -0,0 +1,25 @@ +import type { CustomRegExpSource, ParsedCustomRegExp, CustomRegExpSourceList } from "@lib/common/models/shared.type.util"; +import type { ObsidianLiveSyncSettings, RemoteDBSettings } from "@lib/common/models/setting.type"; +/*** + * Parse custom regular expression + * @param regexp + * @returns [negate: boolean, regexp: string] + * @example `!!foo` => [true, "foo"] + * @example `foo` => [false, "foo"] + */ +export declare function parseCustomRegExp(regexp: CustomRegExpSource): ParsedCustomRegExp; +export declare function matchRegExp(regexp: CustomRegExpSource, target: string): boolean; +export declare function isValidRegExp(regexp: CustomRegExpSource): boolean; +export declare function isInvertedRegExp(regexp: CustomRegExpSource): boolean; +export declare function constructCustomRegExpList(items: CustomRegExpSource[], delimiter: D): CustomRegExpSourceList; +export declare function splitCustomRegExpList(list: CustomRegExpSourceList, delimiter: D): CustomRegExpSource[]; +export declare class CustomRegExp { + regexp: RegExp; + negate: boolean; + pattern: string; + constructor(regexp: CustomRegExpSource, flags?: string); + test(str: string): boolean; +} +type RegExpSettingKey = "syncOnlyRegEx" | "syncIgnoreRegEx" | "syncInternalFilesIgnorePatterns" | "syncInternalFilesTargetPatterns" | "syncInternalFileOverwritePatterns"; +export declare function getFileRegExp(settings: ObsidianLiveSyncSettings | RemoteDBSettings, key: RegExpSettingKey): CustomRegExp[]; +export {}; diff --git a/_types/lib/src/common/utils.settings.d.ts b/_types/lib/src/common/utils.settings.d.ts new file mode 100644 index 0000000..1988126 --- /dev/null +++ b/_types/lib/src/common/utils.settings.d.ts @@ -0,0 +1,19 @@ +import type { ObsidianLiveSyncSettings, P2PConnectionInfo, BucketSyncSetting, CouchDBConnection, EncryptionSettings } from "@lib/common/models/setting.type"; +/** + * Copies properties from the source object to the target object only if they exist in the target. + * @param source The object to copy properties from. + * @param target The object to copy properties to. + */ +export declare function copyTo(source: U, target: T): void; +export declare function pickBucketSyncSettings(setting: ObsidianLiveSyncSettings): BucketSyncSetting; +export declare function pickCouchDBSyncSettings(setting: ObsidianLiveSyncSettings): CouchDBConnection; +export declare function pickEncryptionSettings(setting: ObsidianLiveSyncSettings | EncryptionSettings): EncryptionSettings; +export declare function pickP2PSyncSettings(setting: Partial & P2PConnectionInfo): P2PConnectionInfo; +/** + * Generate a random P2P Room ID in the format `123-456-789-abc`. + */ +export declare function generateP2PRoomId(): string; +/** + * Extract the stable suffix (last segment) from a Room ID. + */ +export declare function extractP2PRoomSuffix(roomId: string): string; diff --git a/_types/lib/src/common/utils.timer.d.ts b/_types/lib/src/common/utils.timer.d.ts new file mode 100644 index 0000000..7424139 --- /dev/null +++ b/_types/lib/src/common/utils.timer.d.ts @@ -0,0 +1,18 @@ +/** + * Run task with keeping minimum interval + * @param key waiting key + * @param interval interval (ms) + * @param task task to perform. + * @returns result of task + * @remarks This function is not designed to be concurrent. + */ +export declare function runWithInterval(key: string, interval: number, task: () => Promise): Promise; +/** + * Run task with keeping minimum interval on start + * @param key waiting key + * @param interval interval (ms) + * @param task task to perform. + * @returns result of task + * @remarks This function is not designed to be concurrent. + */ +export declare function runWithStartInterval(key: string, interval: number, task: () => Promise): Promise; diff --git a/_types/lib/src/dataobject/StoredMap.d.ts b/_types/lib/src/dataobject/StoredMap.d.ts new file mode 100644 index 0000000..0451cf5 --- /dev/null +++ b/_types/lib/src/dataobject/StoredMap.d.ts @@ -0,0 +1,12 @@ +import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase"; +export declare class StoredMapLike { + _store: SimpleStore; + _cache: Map; + _prefix: string; + constructor(store: SimpleStore>, prefix?: string); + addPrefix(key: string): string; + get(key: string): Promise; + set(key: string, value: U): Promise; + delete(key: string): Promise; + has(key: string): Promise; +} diff --git a/_types/lib/src/dev/checks.d.ts b/_types/lib/src/dev/checks.d.ts new file mode 100644 index 0000000..0da7cc5 --- /dev/null +++ b/_types/lib/src/dev/checks.d.ts @@ -0,0 +1,5 @@ +type InstanceHaveOnBindFunction = { + onBindFunction: (core: any, services: any) => void; +} & Record; +export declare function __$checkInstanceBinding(instance: T): void; +export {}; diff --git a/_types/lib/src/encryption/encryptHKDF.d.ts b/_types/lib/src/encryption/encryptHKDF.d.ts new file mode 100644 index 0000000..dd79d2c --- /dev/null +++ b/_types/lib/src/encryption/encryptHKDF.d.ts @@ -0,0 +1,3 @@ +import { encryptHKDFWorker, decryptHKDFWorker } from "@lib/worker/bgWorker.ts"; +export declare const encryptHKDF: typeof encryptHKDFWorker; +export declare const decryptHKDF: typeof decryptHKDFWorker; diff --git a/_types/lib/src/encryption/stringEncryption.d.ts b/_types/lib/src/encryption/stringEncryption.d.ts new file mode 100644 index 0000000..0b71663 --- /dev/null +++ b/_types/lib/src/encryption/stringEncryption.d.ts @@ -0,0 +1,27 @@ +/** + * Encrypts a string using a passphrase, unless the string is already encrypted. + * + * If the input string begins with `ENCRYPT_V2_PREFIX` or `HKDF_SALTED_ENCRYPTED_PREFIX`, + * we assume it is already encrypted and return it unchanged. + * Otherwise, we encrypt the string using an ephemeral salt and the provided passphrase. + * + * @param source - The plaintext string to encrypt, or an already encrypted string. + * @param passphrase - The passphrase used for encryption. + * @returns A promise resolving to the encrypted string, or the original string if it is already encrypted. + */ +export declare function encryptString(source: string, passphrase: string): Promise; +/** + * Decrypts an encrypted string using the provided passphrase. + * + * This function determines the encryption format by inspecting the string prefix, then applies + * the appropriate decryption method. It supports several encryption formats, including + * HKDF salted encryption and legacy formats (V1, V2, V3). If the format is not supported, + * an error is thrown. + * + * @param encrypted - The encrypted string to decrypt. + * @param passphrase - The passphrase used for decryption. + * @returns A promise resolving to the decrypted string. + * @throws {Error} If the encryption format is unsupported. + */ +export declare function decryptString(encrypted: string, passphrase: string): Promise; +export declare function tryDecryptString(encrypted: string, passphrase: string | false): Promise; diff --git a/_types/lib/src/events/coreEvents.d.ts b/_types/lib/src/events/coreEvents.d.ts new file mode 100644 index 0000000..6481df0 --- /dev/null +++ b/_types/lib/src/events/coreEvents.d.ts @@ -0,0 +1,55 @@ +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +export declare const EVENT_LAYOUT_READY = "layout-ready"; +export declare const EVENT_PLUGIN_LOADED = "plugin-loaded"; +export declare const EVENT_PLUGIN_UNLOADED = "plugin-unloaded"; +export declare const EVENT_SETTING_SAVED = "setting-saved"; +export declare const EVENT_FILE_RENAMED = "file-renamed"; +export declare const EVENT_FILE_SAVED = "file-saved"; +export declare const EVENT_LEAF_ACTIVE_CHANGED = "leaf-active-changed"; +export declare const EVENT_DATABASE_REBUILT = "database-rebuilt"; +export declare const EVENT_LOG_ADDED = "log-added"; +export declare const EVENT_REQUEST_OPEN_SETUP_URI = "request-open-setup-uri"; +export declare const EVENT_REQUEST_COPY_SETUP_URI = "request-copy-setup-uri"; +export declare const EVENT_REQUEST_SHOW_SETUP_QR = "request-show-setup-qr"; +export declare const EVENT_REQUEST_RELOAD_SETTING_TAB = "reload-setting-tab"; +export declare const EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG = "request-open-plugin-sync-dialog"; +export declare const EVENT_FILE_CHANGED = "event-file-changed"; +export declare const EVENT_DOCUMENT_STUB_CREATED = "document-stub-created"; +export declare const EVENT_REQUEST_OPEN_P2P_SETTINGS = "request-open-p2p-settings"; +export declare const EVENT_REQUEST_OPEN_P2P = "request-open-p2p"; +export declare const EVENT_REQUEST_CLOSE_P2P = "request-close-p2p"; +export declare const EVENT_PLATFORM_UNLOADED = "platform-unloaded"; +export declare const EVENT_ON_UNRESOLVED_ERROR = "on-unresolved-error"; +export declare const EVENT_REQUEST_CHECK_REMOTE_SIZE = "request-check-remote-size"; +declare global { + interface LSEvents { + [EVENT_FILE_SAVED]: undefined; + [EVENT_SETTING_SAVED]: ObsidianLiveSyncSettings; + [EVENT_LAYOUT_READY]: undefined; + [EVENT_FILE_CHANGED]: { + file: FilePathWithPrefix; + automated: boolean; + }; + [EVENT_DOCUMENT_STUB_CREATED]: { + toc: Set; + stub: { + [key: string]: { + [key: string]: Map>; + }; + }; + }; + [EVENT_FILE_RENAMED]: { + newPath: FilePathWithPrefix; + old: FilePathWithPrefix; + }; + [EVENT_DATABASE_REBUILT]: undefined; + [EVENT_REQUEST_OPEN_P2P_SETTINGS]: undefined; + [EVENT_REQUEST_SHOW_SETUP_QR]: undefined; + [EVENT_REQUEST_OPEN_P2P]: undefined; + [EVENT_REQUEST_CLOSE_P2P]: undefined; + [EVENT_PLATFORM_UNLOADED]: undefined; + [EVENT_ON_UNRESOLVED_ERROR]: undefined; + [EVENT_REQUEST_CHECK_REMOTE_SIZE]: undefined; + } +} diff --git a/_types/lib/src/hub/hub.d.ts b/_types/lib/src/hub/hub.d.ts new file mode 100644 index 0000000..e88de39 --- /dev/null +++ b/_types/lib/src/hub/hub.d.ts @@ -0,0 +1,8 @@ +import { EventHub } from "octagonal-wheels/events"; +declare global { + interface LSEvents { + hello: string; + world: undefined; + } +} +export declare const eventHub: EventHub; diff --git a/_types/lib/src/index.d.ts b/_types/lib/src/index.d.ts new file mode 100644 index 0000000..b8c410d --- /dev/null +++ b/_types/lib/src/index.d.ts @@ -0,0 +1 @@ +export { DirectFileManipulator, type DirectFileManipulatorOptions } from "./API/DirectFileManipulator.ts"; diff --git a/_types/lib/src/interfaces/Confirm.d.ts b/_types/lib/src/interfaces/Confirm.d.ts new file mode 100644 index 0000000..ca6ffc5 --- /dev/null +++ b/_types/lib/src/interfaces/Confirm.d.ts @@ -0,0 +1,17 @@ +export interface Confirm { + askYesNo(message: string): Promise<"yes" | "no">; + askString(title: string, key: string, placeholder: string, isPassword?: boolean): Promise; + askYesNoDialog(message: string, opt: { + title?: string; + defaultOption?: "Yes" | "No"; + timeout?: number; + }): Promise<"yes" | "no">; + askSelectString(message: string, items: string[]): Promise; + askSelectStringDialogue(message: string, buttons: T, opt: { + title?: string; + defaultAction: T[number]; + timeout?: number; + }): Promise; + askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void): void; + confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>; +} diff --git a/_types/lib/src/interfaces/DatabaseFileAccess.d.ts b/_types/lib/src/interfaces/DatabaseFileAccess.d.ts new file mode 100644 index 0000000..c640907 --- /dev/null +++ b/_types/lib/src/interfaces/DatabaseFileAccess.d.ts @@ -0,0 +1,15 @@ +import type { FilePathWithPrefix, LoadedEntry, MetaEntry } from "@lib/common/models/db.type"; +import type { UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +export interface DatabaseFileAccess { + delete: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string) => Promise; + store: (file: UXFileInfo, force?: boolean, skipCheck?: boolean) => Promise; + storeAsConflictedRevision: (file: UXFileInfo, currentRev: string, skipCheck?: boolean) => Promise; + storeContent(path: FilePathWithPrefix, content: string): Promise; + createChunks: (file: UXFileInfo, force?: boolean, skipCheck?: boolean) => Promise; + hasContentInRevisionHistory: (file: UXFileInfoStub | FilePathWithPrefix, content: string | string[] | Blob | ArrayBuffer, currentRev?: string) => Promise; + fetch: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string, waitForReady?: boolean, skipCheck?: boolean) => Promise; + fetchEntryFromMeta: (meta: MetaEntry, waitForReady?: boolean, skipCheck?: boolean) => Promise; + fetchEntryMeta: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string, skipCheck?: boolean) => Promise; + fetchEntry: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string, waitForReady?: boolean, skipCheck?: boolean) => Promise; + getConflictedRevs: (file: UXFileInfoStub | FilePathWithPrefix) => Promise; +} diff --git a/_types/lib/src/interfaces/DatabaseRebuilder.d.ts b/_types/lib/src/interfaces/DatabaseRebuilder.d.ts new file mode 100644 index 0000000..7ff3c00 --- /dev/null +++ b/_types/lib/src/interfaces/DatabaseRebuilder.d.ts @@ -0,0 +1,13 @@ +export interface Rebuilder { + $performRebuildDB(method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks"): Promise; + $rebuildRemote(): Promise; + $rebuildEverything(): Promise; + $fetchLocal(makeLocalChunkBeforeSync?: boolean, preventMakeLocalFilesBeforeSync?: boolean): Promise; + $fetchLocalDBFast(autoResume: boolean): Promise; + scheduleRebuild(): Promise; + scheduleFetch(): Promise; + /** + * Declares the finish of the rebuild process and unlock remote, resume reflecting the changes. + */ + finishRebuild(): Promise; +} diff --git a/_types/lib/src/interfaces/FileHandler.d.ts b/_types/lib/src/interfaces/FileHandler.d.ts new file mode 100644 index 0000000..cc7b2f5 --- /dev/null +++ b/_types/lib/src/interfaces/FileHandler.d.ts @@ -0,0 +1,12 @@ +import type { FilePath, FilePathWithPrefix, MetaEntry } from "@lib/common/models/db.type"; +import type { UXFileInfo, UXFileInfoStub, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +export interface IFileHandler { + readFileFromStub(file: UXFileInfoStub | UXFileInfo): Promise; + storeFileToDB(info: UXFileInfoStub | UXFileInfo | UXInternalFileInfoStub | FilePathWithPrefix, force?: boolean, onlyChunks?: boolean): Promise; + deleteFileFromDB(info: UXFileInfoStub | UXInternalFileInfoStub | FilePath): Promise; + deleteRevisionFromDB(info: UXFileInfoStub | FilePath | FilePathWithPrefix, rev: string): Promise; + resolveConflictedByDeletingRevision(info: UXFileInfoStub | FilePath, rev: string): Promise; + dbToStorageWithSpecificRev(info: UXFileInfoStub | UXFileInfo | FilePath | null, rev: string, force?: boolean): Promise; + dbToStorage(entryInfo: MetaEntry | FilePathWithPrefix, info: UXFileInfoStub | UXFileInfo | FilePath | null, force?: boolean): Promise; + createAllChunks(showingNotice?: boolean): Promise; +} diff --git a/_types/lib/src/interfaces/KeyValueDatabase.d.ts b/_types/lib/src/interfaces/KeyValueDatabase.d.ts new file mode 100644 index 0000000..ff1fa79 --- /dev/null +++ b/_types/lib/src/interfaces/KeyValueDatabase.d.ts @@ -0,0 +1,9 @@ +export interface KeyValueDatabase { + get(key: IDBValidKey): Promise; + set(key: IDBValidKey, value: T): Promise; + del(key: IDBValidKey): Promise; + clear(): Promise; + keys(query?: IDBValidKey | IDBKeyRange, count?: number): Promise; + close(): Promise; + destroy(): Promise; +} diff --git a/_types/lib/src/interfaces/ServiceModule.d.ts b/_types/lib/src/interfaces/ServiceModule.d.ts new file mode 100644 index 0000000..1d95221 --- /dev/null +++ b/_types/lib/src/interfaces/ServiceModule.d.ts @@ -0,0 +1,59 @@ +import type { DatabaseFileAccess } from "./DatabaseFileAccess"; +import type { Rebuilder } from "./DatabaseRebuilder"; +import type { IFileHandler } from "./FileHandler"; +import type { StorageAccess } from "./StorageAccess"; +import type { LogFunction } from "@lib/services/lib/logUtils"; +import type { ServiceHub } from "@lib/services/ServiceHub"; +import type { IServiceHub } from "@lib/services/base/IService"; +export interface ServiceModules { + storageAccess: StorageAccess; + /** + * Database File Accessor for handling file operations related to the database, such as exporting the database, importing from a file, etc. + */ + databaseFileAccess: DatabaseFileAccess; + /** + * File Handler for handling file operations related to replication, such as resolving conflicts, applying changes from replication, etc. + */ + fileHandler: IFileHandler; + /** + * Rebuilder for handling database rebuilding operations. + */ + rebuilder: Rebuilder; +} +export type RequiredServices = Pick; +export type RequiredServiceModules = Pick; +export type RequiredServicesInterfaces = Pick; +export type RequiredServiceModulesInterfaces = Pick; +export type NecessaryServices = { + services: RequiredServices; + serviceModules: RequiredServiceModules; +}; +export type NecessaryServicesInterfaces = { + services: RequiredServicesInterfaces; + serviceModules: RequiredServiceModulesInterfaces; +}; +export type ServiceFeatureFunction = (host: NecessaryServices) => TR; +type ServiceFeatureContext = T & { + _log: LogFunction; +}; +export type ServiceFeatureFunctionWithContext = (host: NecessaryServices, context: ServiceFeatureContext) => TR; +/** + * Helper function to create a service feature with proper typing. + * @param featureFunction The feature function to be wrapped. + * @returns The same feature function with proper typing. + * @example + * const myFeatureDef = createServiceFeature(({ services: { API }, serviceModules: { storageAccess } }) => { + * // ... + * }); + * const myFeature = myFeatureDef.bind(null, this); // <- `this` may `ObsidianLiveSyncPlugin` or a custom context object + * appLifecycle.onLayoutReady(myFeature); + */ +export declare function createServiceFeature(featureFunction: ServiceFeatureFunction): ServiceFeatureFunction; +type ContextFactory = (host: NecessaryServices) => ServiceFeatureContext; +export declare function serviceFeature(): { + create(featureFunction: ServiceFeatureFunction): ServiceFeatureFunction; + withContext(ContextFactory: ContextFactory): { + create: (featureFunction: ServiceFeatureFunctionWithContext) => (host: NecessaryServices, context: ServiceFeatureContext) => TR; + }; +}; +export {}; diff --git a/_types/lib/src/interfaces/StorageAccess.d.ts b/_types/lib/src/interfaces/StorageAccess.d.ts new file mode 100644 index 0000000..4b1875e --- /dev/null +++ b/_types/lib/src/interfaces/StorageAccess.d.ts @@ -0,0 +1,44 @@ +import type { FilePath, FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { UXDataWriteOptions, UXFileInfo, UXFileInfoStub, UXFolderInfo, UXStat } from "@lib/common/models/fileaccess.type"; +import type { CustomRegExp } from "@lib/common/utils.regexp"; +import type { FileWithFileStat, FileWithStatAsProp } from "@lib/common/models/fileaccess.type"; +export interface IStorageAccessManager { + processWriteFile(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise): Promise; + processReadFile(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise): Promise; + isFileProcessing(file: UXFileInfoStub | FilePathWithPrefix): boolean; + recentlyTouched(file: FileWithStatAsProp | FileWithFileStat): boolean; + touch(file: FileWithStatAsProp | FileWithFileStat): void; + clearTouched(): void; +} +export interface StorageAccess { + normalisePath(path: string): string; + restoreState(): Promise; + deleteVaultItem(file: FilePathWithPrefix | UXFileInfoStub | UXFolderInfo): Promise; + writeFileAuto(path: string, data: string | ArrayBuffer, opt?: UXDataWriteOptions): Promise; + readFileAuto(path: string): Promise; + readFileText(path: string): Promise; + isExists(path: string): Promise; + writeHiddenFileAuto(path: string, data: string | ArrayBuffer, opt?: UXDataWriteOptions): Promise; + appendHiddenFile(path: string, data: string, opt?: UXDataWriteOptions): Promise; + stat(path: string): Promise; + statHidden(path: string): Promise; + removeHidden(path: string): Promise; + readHiddenFileAuto(path: string): Promise; + readHiddenFileBinary(path: string): Promise; + readHiddenFileText(path: string): Promise; + isExistsIncludeHidden(path: string): Promise; + ensureDir(path: string): Promise; + triggerFileEvent(event: string, path: string): void; + triggerHiddenFile(path: string): Promise; + getFileStub(path: string): Promise; + readStubContent(stub: UXFileInfoStub): Promise; + getStub(path: string): Promise; + getFiles(): Promise; + getFileNames(): Promise; + touched(file: UXFileInfoStub | FilePathWithPrefix): Promise; + recentlyTouched(file: UXFileInfoStub | FilePathWithPrefix): Promise; + clearTouched(): void; + delete(file: FilePathWithPrefix | UXFileInfoStub | string, force: boolean): Promise; + trash(file: FilePathWithPrefix | UXFileInfoStub | string, system: boolean): Promise; + getFilesIncludeHidden(basePath: string, includeFilter?: CustomRegExp[], excludeFilter?: CustomRegExp[], skipFolder?: string[]): Promise; +} diff --git a/_types/lib/src/interfaces/StorageEventManager.d.ts b/_types/lib/src/interfaces/StorageEventManager.d.ts new file mode 100644 index 0000000..d3cd7bc --- /dev/null +++ b/_types/lib/src/interfaces/StorageEventManager.d.ts @@ -0,0 +1,17 @@ +import type { FileEventType, UXFileInfoStub, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { FilePath } from "@lib/common/models/db.type"; +export type FileEvent = { + type: FileEventType; + file: UXFileInfoStub | UXInternalFileInfoStub; + oldPath?: string; + cachedData?: string; + skipBatchWait?: boolean; + cancelled?: boolean; +}; +export declare abstract class StorageEventManager { + abstract beginWatch(): Promise; + abstract appendQueue(items: FileEvent[], ctx?: unknown): Promise; + abstract isWaiting(filename: FilePath): boolean; + abstract waitForIdle(): Promise; + abstract restoreState(): Promise; +} diff --git a/_types/lib/src/managers/ChangeManager.d.ts b/_types/lib/src/managers/ChangeManager.d.ts new file mode 100644 index 0000000..2317d8c --- /dev/null +++ b/_types/lib/src/managers/ChangeManager.d.ts @@ -0,0 +1,61 @@ +import { FallbackWeakRef } from "octagonal-wheels/common/polyfill"; +/** + * Options for configuring the ChangeManager. + */ +export interface ChangeManagerOptions { + /** + * The PouchDB database instance to monitor for changes. + */ + database: PouchDB.Database; +} +export type ChangeManagerCallback = (change: PouchDB.Core.ChangesResponseChange) => void | Promise; +/** + * Manages and dispatches changes from a PouchDB database to registered callbacks. + * + * @template T The type of documents stored in the PouchDB database. + */ +export declare class ChangeManager { + /** + * The PouchDB database instance being monitored. + */ + _database: PouchDB.Database; + /** + * Creates a new instance of the ChangeManager. + * + * @param options - Configuration options for the ChangeManager. + */ + constructor(options: ChangeManagerOptions); + /** + * A list of registered callbacks wrapped in WeakRefs to avoid memory leaks. + */ + _callbacks: FallbackWeakRef[]; + /** + * Registers a new callback to be invoked when a change occurs. + * + * @param callback - The callback function to register. + */ + addCallback(callback: ChangeManagerCallback): () => void; + removeCallback(callback: ChangeManagerCallback): void; + /** + * The PouchDB changes feed instance, if active. + */ + _changes?: PouchDB.Core.Changes; + /** + * Handles a change event from the PouchDB changes feed. + * + * @param changeResponse - The change response object from the PouchDB changes feed. + */ + _onChange(changeResponse: PouchDB.Core.ChangesResponseChange): Promise; + /** + * Sets up the PouchDB changes feed listener to monitor for database changes. + */ + setupListener(): void; + /** + * Tears down the PouchDB changes feed listener and cleans up resources. + */ + teardown(): void; + /** + * Restarts the PouchDB changes feed listener. + */ + restartWatch(): void; +} diff --git a/_types/lib/src/managers/ChunkFetcher.d.ts b/_types/lib/src/managers/ChunkFetcher.d.ts new file mode 100644 index 0000000..9feea1c --- /dev/null +++ b/_types/lib/src/managers/ChunkFetcher.d.ts @@ -0,0 +1,35 @@ +import type { DocumentID } from "@lib/common/models/db.type"; +import { type ChunkManager } from "./ChunkManager.ts"; +import type { IReplicatorService, ISettingService } from "@lib/services/base/IService.ts"; +export declare const EVENT_MISSING_CHUNKS = "missingChunks"; +export declare const EVENT_MISSING_CHUNK_REMOTE = "missingChunkRemote"; +export declare const EVENT_CHUNK_FETCHED = "chunkFetched"; +export type ChunkFetcherOptions = { + settingService: ISettingService; + chunkManager: ChunkManager; + replicatorService: IReplicatorService; +}; +export declare class ChunkFetcher { + options: ChunkFetcherOptions; + get chunkManager(): ChunkManager; + queue: DocumentID[]; + get interval(): number; + get concurrency(): number; + abort: AbortController; + constructor(options: ChunkFetcherOptions); + destroy(): void; + onEventHandler: (ids: DocumentID[]) => void; + onEvent(ids: DocumentID[]): void; + /** + * Processing requests + */ + currentProcessing: number; + /** + * Time of the last request to the remote server. + * This is used to manage the interval between requests. + * Even if concurrency allows, every start of a request will ensure that the interval is respected. + */ + previousRequestTime: number; + canRequestMore(): boolean; + requestMissingChunks(): Promise; +} diff --git a/_types/lib/src/managers/ChunkManager.d.ts b/_types/lib/src/managers/ChunkManager.d.ts new file mode 100644 index 0000000..1c0a3b1 --- /dev/null +++ b/_types/lib/src/managers/ChunkManager.d.ts @@ -0,0 +1,2 @@ +import { LayeredChunkManager } from "./LayeredChunkManager"; +export { LayeredChunkManager as ChunkManager }; diff --git a/_types/lib/src/managers/ConflictManager.d.ts b/_types/lib/src/managers/ConflictManager.d.ts new file mode 100644 index 0000000..d95eddf --- /dev/null +++ b/_types/lib/src/managers/ConflictManager.d.ts @@ -0,0 +1,39 @@ +import { type Diff } from "diff-match-patch"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { FilePathWithPrefix, LoadedEntry } from "@lib/common/models/db.type"; +import type { diff_result_leaf, DIFF_CHECK_RESULT_AUTO } from "@lib/common/models/diff.definition"; +import type { EntryManager } from "./EntryManager/EntryManager.ts"; +import type { IPathService } from "@lib/services/base/IService.ts"; +type AutoMergeOutcomeOK = { + ok: DIFF_CHECK_RESULT_AUTO; +}; +type AutoMergeCanBeDoneByDeletingRev = { + result: string; + conflictedRev: string; +}; +type UserActionRequired = { + leftRev: string; + rightRev: string; + leftLeaf: diff_result_leaf | false; + rightLeaf: diff_result_leaf | false; +}; +export type AutoMergeResult = Promise; +export interface ConflictManagerOptions { + entryManager: EntryManager; + pathService: IPathService; + database: PouchDB.Database; +} +export declare class ConflictManager { + options: ConflictManagerOptions; + constructor(options: ConflictManagerOptions); + get database(): PouchDB.Database; + getConflictedDoc(path: FilePathWithPrefix, rev: string): Promise; + mergeSensibly(path: FilePathWithPrefix, baseRev: string, currentRev: string, conflictedRev: string): Promise; + mergeObject(path: FilePathWithPrefix, baseRev: string, currentRev: string, conflictedRev: string): Promise; + tryAutoMergeSensibly(path: FilePathWithPrefix, test: LoadedEntry, conflicts: string[]): Promise; + tryAutoMerge(path: FilePathWithPrefix, enableMarkdownAutoMerge: boolean): AutoMergeResult; +} +export {}; diff --git a/_types/lib/src/managers/EntryManager/EntryManager.d.ts b/_types/lib/src/managers/EntryManager/EntryManager.d.ts new file mode 100644 index 0000000..f284247 --- /dev/null +++ b/_types/lib/src/managers/EntryManager/EntryManager.d.ts @@ -0,0 +1,38 @@ +import type { FilePathWithPrefix, FilePath, LoadedEntry, SavingEntry, MetaEntry } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { ChunkManager } from "@lib/managers/ChunkManager"; +import type { ContentSplitter } from "@lib/ContentSplitter/ContentSplitters"; +import type { HashManager } from "@lib/managers/HashManager/HashManager"; +import type { GeneratedChunk } from "@lib/pouchdb/LiveSyncLocalDB"; +import type { IPathService, ISettingService } from "@lib/services/base/IService"; +export interface EntryManagerOptions { + hashManager: HashManager; + chunkManager: ChunkManager; + splitter: ContentSplitter; + database: PouchDB.Database; + settingService: ISettingService; + pathService: IPathService; +} +export declare class EntryManager { + options: EntryManagerOptions; + constructor(options: EntryManagerOptions); + get localDatabase(): PouchDB.Database; + get hashManager(): HashManager; + get chunkManager(): ChunkManager; + get splitter(): ContentSplitter; + get serviceHost(): { + services: { + setting: ISettingService; + path: IPathService; + }; + serviceModules: {}; + }; + get isOnDemandChunkEnabled(): boolean; + isTargetFile(filenameSrc: string): boolean; + prepareChunk(piece: string): Promise; + getDBEntryMeta(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, includeDeleted?: boolean): Promise; + getDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, dump?: boolean, waitForReady?: boolean, includeDeleted?: boolean): Promise; + getDBEntryFromMeta(meta: LoadedEntry | MetaEntry, dump?: boolean, waitForReady?: boolean): Promise; + deleteDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions): Promise; + putDBEntry(note: SavingEntry, onlyChunks?: boolean, conflictBaseRev?: string): Promise; +} diff --git a/_types/lib/src/managers/EntryManager/EntryManagerImpls.d.ts b/_types/lib/src/managers/EntryManager/EntryManagerImpls.d.ts new file mode 100644 index 0000000..8211291 --- /dev/null +++ b/_types/lib/src/managers/EntryManager/EntryManagerImpls.d.ts @@ -0,0 +1,28 @@ +import type { SavingEntry, DocumentID, FilePath, FilePathWithPrefix, LoadedEntry, MetaEntry, NoteEntry } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import type { ContentSplitter } from "@lib/ContentSplitter/ContentSplitters"; +import type { HashManager } from "@lib/managers/HashManager/HashManager"; +import type { LayeredChunkManager as ChunkManager } from "@lib/managers/LayeredChunkManager"; +import type { NecessaryServicesInterfaces } from "@lib/interfaces/ServiceModule"; +import type { GeneratedChunk } from "@lib/pouchdb/LiveSyncLocalDB"; +type Managers = { + hashManager: HashManager; + chunkManager: ChunkManager; + splitter: ContentSplitter; + localDatabase: PouchDB.Database; +}; +type NecessaryManagers = Pick; +export declare function createChunks(managers: NecessaryManagers<"chunkManager" | "hashManager" | "splitter">, dispFilename: string, note: SavingEntry): Promise; +export declare function putDBEntry(host: NecessaryServicesInterfaces<"path" | "setting", never>, managers: NecessaryManagers<"localDatabase" | "chunkManager" | "hashManager" | "splitter">, note: SavingEntry, onlyChunks?: boolean, conflictBaseRev?: string): Promise; +export declare function isTargetFile(host: NecessaryServicesInterfaces<"setting", never>, filenameSrc: string): boolean; +export declare function prepareChunk({ chunkManager, hashManager }: NecessaryManagers<"chunkManager" | "hashManager">, piece: string): Promise; +export declare function getDBEntryMetaByPath(host: NecessaryServicesInterfaces<"path" | "setting", never>, { localDatabase }: NecessaryManagers<"localDatabase">, path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, includeDeleted?: boolean): Promise; +export declare function isLegacyNote(meta: LoadedEntry | MetaEntry): meta is NoteEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; +}; +export declare function canUseOnDemandChunking(settings: ObsidianLiveSyncSettings): boolean; +export declare function getDBEntryFromMeta(host: NecessaryServicesInterfaces<"path" | "setting", never>, { localDatabase, chunkManager }: NecessaryManagers<"localDatabase" | "chunkManager">, meta: LoadedEntry | MetaEntry, dump?: boolean, waitForReady?: boolean): Promise; +export declare function getDBEntryByPath(host: NecessaryServicesInterfaces<"path" | "setting", never>, managers: NecessaryManagers<"localDatabase" | "chunkManager">, path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, dump?: boolean, waitForReady?: boolean, includeDeleted?: boolean): Promise; +export declare function deleteDBEntryByPath(host: NecessaryServicesInterfaces<"path" | "setting", never>, { localDatabase }: NecessaryManagers<"localDatabase">, path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions): Promise; +export {}; diff --git a/_types/lib/src/managers/HashManager/HashManager.d.ts b/_types/lib/src/managers/HashManager/HashManager.d.ts new file mode 100644 index 0000000..d410998 --- /dev/null +++ b/_types/lib/src/managers/HashManager/HashManager.d.ts @@ -0,0 +1,60 @@ +import type { HashAlgorithm } from "@lib/common/models/setting.type.ts"; +import { HashManagerCore, type HashManagerCoreOptions } from "./HashManagerCore.ts"; +/** + * Class for managing hash managers and performing hash calculations. + * Selects an appropriate manager according to the available hash algorithm. + */ +export declare class HashManager extends HashManagerCore { + /** + * Instance of the hash manager currently in use. + */ + manager: HashManagerCore; + /** + * Checks whether the specified hash algorithm is available. + * + * @param hashAlg The hash algorithm to check + * @returns True if available + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; + /** + * Selects and initialises an available hash manager. + * + * @returns True if initialisation is successful + * @throws Throws an error if no available manager exists + */ + setManager(): Promise; + /** + * Constructs a new HashManager. + * + * @param options Initialisation options + */ + constructor(options: HashManagerCoreOptions); + /** + * Initialises the hash manager. + * + * @returns True if initialisation is successful + * @throws Throws an error if initialisation fails + */ + processInitialise(): Promise; + /** + * Computes the hash value for the specified string. + * + * @param piece The string to be hashed + * @returns The hash value (returned as a Promise) + */ + computeHash(piece: string): Promise; + /** + * Computes the hash value without encryption. + * + * @param piece The string to be hashed + * @returns The hash value (returned as a Promise) + */ + computeHashWithoutEncryption(piece: string): Promise; + /** + * Computes the hash value with encryption. + * + * @param piece The string to be hashed + * @returns The hash value (returned as a Promise) + */ + computeHashWithEncryption(piece: string): Promise; +} diff --git a/_types/lib/src/managers/HashManager/HashManagerCore.d.ts b/_types/lib/src/managers/HashManager/HashManagerCore.d.ts new file mode 100644 index 0000000..ea6f4b8 --- /dev/null +++ b/_types/lib/src/managers/HashManager/HashManagerCore.d.ts @@ -0,0 +1,114 @@ +import type { ISettingService } from "@lib/services/base/IService.ts"; +import type { HashAlgorithm } from "@lib/common/models/setting.type.ts"; +/** + * Prefix for encrypted hashes. + * + * This constant is prepended to hash strings when encryption is enabled. + */ +export declare const HashEncryptedPrefix = "+"; +/** + * Options for initialising {@link HashManagerCore}. + */ +export type HashManagerCoreOptions = { + /** + * Remote database settings used for hash management. + */ + settingService: ISettingService; +}; +/** + * Abstract base class for hash management. + * + * Provides core logic for handling passphrase hashing, encryption toggling, + * and initialisation routines. Subclasses should implement encryption-specific + * hash computation methods. + */ +export declare abstract class HashManagerCore { + protected settingService: ISettingService; + /** + * Indicates whether encryption is enabled for hash computation. + */ + useEncryption: boolean; + /** + * Hashed passphrase as a string, used for hash operations. + */ + hashedPassphrase: string; + /** + * Hashed passphrase as a 32-bit number, used for hash operations. + */ + hashedPassphrase32: number; + /** + * Options used for initialisation and configuration. + */ + options: HashManagerCoreOptions; + /** + * Constructs a new {@link HashManagerCore} instance. + * + * @param options - Configuration options for hash management. + */ + constructor(options: HashManagerCoreOptions); + /** + * Applies the given options to the hash manager. + * + * Updates encryption settings and computes passphrase hashes. + * + * @param options - Optional configuration to apply. + */ + applyOptions(options?: HashManagerCoreOptions): void; + /** + * Performs initialisation logic specific to the hash manager implementation. + * + * Subclasses must implement this method. + * + * @returns Promise resolving to true if initialisation succeeds. + */ + abstract processInitialise(): Promise; + /** + * Task representing the initialisation process. + */ + initialiseTask?: Promise; + /** + * Ensures the hash manager is initialised. + * + * Returns a promise that resolves when initialisation is complete. + * + * @returns Promise resolving to true if initialisation succeeds. + */ + initialise(): Promise; + /** + * Computes a hash for the given string. + * + * If encryption is enabled, the hash is computed with encryption and prefixed. + * Otherwise, a plain hash is computed. + * + * @param piece - The input string to hash. + * @returns Promise resolving to the computed hash string. + */ + computeHash(piece: string): Promise; + /** + * Computes a hash for the given string without encryption. + * + * Subclasses must implement this method. + * + * @param piece - The input string to hash. + * @returns Promise resolving to the computed hash string. + */ + abstract computeHashWithoutEncryption(piece: string): Promise; + /** + * Computes a hash for the given string with encryption. + * + * Subclasses must implement this method. + * + * @param piece - The input string to hash. + * @returns Promise resolving to the computed encrypted hash string. + */ + abstract computeHashWithEncryption(piece: string): Promise; + /** + * Determines whether the hash manager is available for the specified algorithm. + * + * Subclasses should override this method to indicate supported algorithms. + * + * @param hashAlg - The hash algorithm to check. + * @returns True if available, false otherwise. + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; +} diff --git a/_types/lib/src/managers/HashManager/PureJSHashManager.d.ts b/_types/lib/src/managers/HashManager/PureJSHashManager.d.ts new file mode 100644 index 0000000..b70a80f --- /dev/null +++ b/_types/lib/src/managers/HashManager/PureJSHashManager.d.ts @@ -0,0 +1,77 @@ +import { HashManagerCore } from "./HashManagerCore.ts"; +import type { HashAlgorithm } from "@lib/common/models/setting.type.ts"; +/** + * Provides hash management using the "mixed-purejs" algorithm. + * + * This manager utilises a pure JavaScript implementation for hashing. + * It is available only when the hash algorithm is set to "mixed-purejs". + */ +export declare class PureJSHashManager extends HashManagerCore { + /** + * Determines whether this manager is available for the specified algorithm. + * @param hashAlg The hash algorithm to check. + * @returns True if the algorithm is "mixed-purejs". + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; + /** + * Initialises the hash manager. + * @returns Always resolves to true. + */ + processInitialise(): Promise; + /** + * Computes a hash for the given input, including encryption. + * @param input The input string to hash. + * @returns The computed hash as a promise. + */ + computeHashWithEncryption(input: string): Promise; + /** + * Computes a hash for the given input, without encryption. + * @param input The input string to hash. + * @returns The computed hash as a promise. + */ + computeHashWithoutEncryption(input: string): Promise; +} +/** + * Provides hash management using the "sha1" algorithm. + * + * This manager utilises a pure JavaScript SHA-1 implementation. + * It is available only when the hash algorithm is set to "sha1". + */ +export declare class SHA1HashManager extends HashManagerCore { + /** + * Determines whether this manager is available for the specified algorithm. + * @param hashAlg The hash algorithm to check. + * @returns True if the algorithm is "sha1". + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; + /** + * Initialises the hash manager. + * @returns Always resolves to true. + */ + processInitialise(): Promise; + /** + * Computes a SHA-1 hash for the given input, including encryption. + * @param input The input string to hash. + * @returns The computed SHA-1 hash as a promise. + */ + computeHashWithEncryption(input: string): Promise; + /** + * Computes a SHA-1 hash for the given input, without encryption. + * @param input The input string to hash. + * @returns The computed SHA-1 hash as a promise. + */ + computeHashWithoutEncryption(input: string): Promise; +} +/** + * Fallback hash manager using the pure JavaScript implementation. + * + * This manager is always available and acts as a fallback when no specific algorithm matches. + */ +export declare class FallbackPureJSHashManager extends PureJSHashManager { + /** + * Always returns true, indicating this manager is available for any algorithm. + * @param _hashAlg The hash algorithm (ignored). + * @returns True. + */ + static isAvailableFor(_hashAlg: HashAlgorithm): boolean; +} diff --git a/_types/lib/src/managers/HashManager/XXHashHashManager.d.ts b/_types/lib/src/managers/HashManager/XXHashHashManager.d.ts new file mode 100644 index 0000000..7d3ca67 --- /dev/null +++ b/_types/lib/src/managers/HashManager/XXHashHashManager.d.ts @@ -0,0 +1,96 @@ +import { HashManagerCore, type HashManagerCoreOptions } from "./HashManagerCore.ts"; +import type { XXHashAPI } from "xxhash-wasm-102"; +import type { HashAlgorithm } from "@lib/common/models/setting.type.ts"; +/** + * Abstract base class for hash managers using XXHash algorithms. + * Provides initialisation and common properties for XXHash-based managers. + */ +export declare abstract class XXHashHashManager extends HashManagerCore { + /** + * Instance of XXHash API used for hashing operations. + */ + xxhash: XXHashAPI; + /** + * Constructs a new XXHashHashManager. + * @param options - Options for the hash manager core. + */ + constructor(options: HashManagerCoreOptions); + /** + * Initialises the XXHash API instance. + * @returns A promise resolving to true when initialisation is complete. + */ + processInitialise(): Promise; +} +/** + * Hash manager for the legacy hash algorithm (empty string). + * Utilises XXHash32 raw hashing. + */ +export declare class XXHash32RawHashManager extends XXHashHashManager { + /** + * Determines whether this manager is available for the specified algorithm. + * @param hashAlg - The hash algorithm to check. + * @returns True if available, false otherwise. + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; + /** + * Computes a hash for the given piece using encryption. + * @param piece - The input string to hash. + * @returns A promise resolving to the hash string. + */ + computeHashWithEncryption(piece: string): Promise; + /** + * Computes a hash for the given piece without encryption. + * @param piece - The input string to hash. + * @returns A promise resolving to the hash string. + */ + computeHashWithoutEncryption(piece: string): Promise; +} +/** + * Hash manager for the XXHash64 algorithm ("xxhash64"). + */ +export declare class XXHash64HashManager extends XXHashHashManager { + /** + * Determines whether this manager is available for the specified algorithm. + * @param hashAlg - The hash algorithm to check. + * @returns True if available, false otherwise. + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; + /** + * Computes a hash for the given piece using encryption. + * @param piece - The input string to hash. + * @returns A promise resolving to the hash string. + */ + computeHashWithEncryption(piece: string): Promise; + /** + * Computes a hash for the given piece without encryption. + * @param piece - The input string to hash. + * @returns A promise resolving to the hash string. + */ + computeHashWithoutEncryption(piece: string): Promise; +} +/** + * Fallback hash manager utilising XXHash32. + * Used when no specific algorithm is matched. + * Please be careful with this manager, as it is different from XXHash32RawHashManager. + */ +export declare class FallbackWasmHashManager extends XXHashHashManager { + /** + * Determines whether this manager is available for the specified algorithm. + * Always returns true as a fallback. + * @param hashAlg - The hash algorithm to check. + * @returns True. + */ + static isAvailableFor(hashAlg: HashAlgorithm): boolean; + /** + * Computes a hash for the given piece using encryption. + * @param piece - The input string to hash. + * @returns A promise resolving to the hash string. + */ + computeHashWithEncryption(piece: string): Promise; + /** + * Computes a hash for the given piece without encryption. + * @param piece - The input string to hash. + * @returns A promise resolving to the hash string. + */ + computeHashWithoutEncryption(piece: string): Promise; +} diff --git a/_types/lib/src/managers/LayeredChunkManager.d.ts b/_types/lib/src/managers/LayeredChunkManager.d.ts new file mode 100644 index 0000000..6e272c0 --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager.d.ts @@ -0,0 +1,51 @@ +import type { DocumentID, EntryLeaf } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { ChangeManager } from "./ChangeManager.ts"; +import type { ChunkManagerEventMap, ChunkManagerOptions, ChunkReadOptions, ChunkWriteOptions, WriteResult } from "./LayeredChunkManager/types.ts"; +/** + * ChunkManager class that manages chunk operations such as reading, writing, and caching. + * Now uses a middleware layer architecture for read and write operations. + */ +export declare class LayeredChunkManager { + protected options: ChunkManagerOptions; + protected eventTarget: EventTarget; + private cacheLayer; + private readLayers; + private writeLayers; + private arrivalWaitLayer; + get changeManager(): ChangeManager; + get database(): PouchDB.Database; + get cacheStatistics(): { + size: number; + allocCount: number; + derefCount: number; + }; + addListener(type: K, listener: (this: LayeredChunkManager, ev: ChunkManagerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): () => void; + emitEvent(type: K, detail: ChunkManagerEventMap[K]): void; + protected abort: AbortController; + protected offChangeHandler: ReturnType; + protected initialised: Promise; + _initialise(): Promise; + constructor(options: ChunkManagerOptions); + destroy(): void; + getCachedChunk(id: DocumentID): EntryLeaf | false; + getChunkIDFromCache(data: string): DocumentID | false; + cacheChunk(chunk: EntryLeaf): void; + clearCaches(): void; + read(ids: DocumentID[], options: ChunkReadOptions, preloadedChunks?: Record): Promise<(EntryLeaf | false)[]>; + private executeReadPipeline; + write(chunks: EntryLeaf[], options: ChunkWriteOptions, origin: DocumentID): Promise; + private executeWritePipeline; + private isChunkDoc; + private onChunkArrived; + protected onChunkArrivedHandler: (doc: EntryLeaf, deleted?: boolean) => void; + private onChange; + protected onChangeHandler: (change: PouchDB.Core.ChangesResponseChange) => void; + onMissingChunkRemote(id: DocumentID): void; + protected onMissingChunkRemoteHandler: (id: DocumentID) => void; + protected concurrentTransactions: number; + protected stabilised: Promise; + transaction(callback: () => Promise): Promise; + _stabilise(): Promise; + __stabilise(): Promise; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/ArrivalWaitLayer.d.ts b/_types/lib/src/managers/LayeredChunkManager/ArrivalWaitLayer.d.ts new file mode 100644 index 0000000..f4adf85 --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/ArrivalWaitLayer.d.ts @@ -0,0 +1,32 @@ +import type { DocumentID, EntryLeaf } from "@lib/common/models/db.type"; +import type { IReadLayer } from "./ChunkLayerInterfaces"; +import type { ChunkReadOptions } from "./types.ts"; +/** + * Arrival wait layer - emits events for fetcher, and waits for chunks to arrive + */ +export declare class ArrivalWaitLayer implements IReadLayer { + private waitingMap; + private readonly DEFAULT_TIMEOUT; + private readonly eventEmitter; + constructor(eventEmitter: (eventName: string, data: DocumentID[]) => void); + private enqueueWaiting; + private withTimeout; + /** + * Handle chunk arrival (called when a chunk document arrives) + */ + onChunkArrived(doc: EntryLeaf, deleted?: boolean): void; + /** + * Handle missing chunk (called when a chunk is confirmed missing) + */ + onMissingChunk(id: DocumentID): void; + read(ids: DocumentID[], options: ChunkReadOptions, next: (remaining: DocumentID[]) => Promise<(EntryLeaf | false)[]>): Promise<(EntryLeaf | false)[]>; + /** + * Clear all waiting requests + */ + clearWaiting(): void; + tearDown(): void; + /** + * Get count of waiting chunks + */ + getWaitingCount(): number; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/CacheLayer.d.ts b/_types/lib/src/managers/LayeredChunkManager/CacheLayer.d.ts new file mode 100644 index 0000000..a3528dd --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/CacheLayer.d.ts @@ -0,0 +1,59 @@ +import type { DocumentID, EntryLeaf } from "@lib/common/models/db.type"; +import type { IReadLayer, IWriteLayer } from "./ChunkLayerInterfaces"; +import type { ChunkReadOptions, ChunkWriteOptions, WriteResult } from "./types.ts"; +/** + * Cache layer - manages in-memory cache of chunks. + * Implements both IReadLayer and IWriteLayer for unified cache management. + * This layer is self-contained and handles cache operations for both read and write operations. + */ +export declare class CacheLayer implements IReadLayer, IWriteLayer { + private caches; + private maxCacheSize; + allocCount: number; + derefCount: number; + constructor(maxCacheSize: number); + /** + * Get a cached chunk + */ + getCachedChunk(id: DocumentID): EntryLeaf | false; + /** + * Find chunk ID by data content + */ + getChunkIDFromCache(data: string): DocumentID | false; + /** + * Cache a chunk + */ + cacheChunk(chunk: EntryLeaf): void; + /** + * Reorder chunk for LRU (move to end) + */ + reorderChunk(id: DocumentID): void; + /** + * Delete a cached chunk + */ + deleteCachedChunk(id: DocumentID): void; + /** + * Clear all caches + */ + clearCaches(): void; + /** + * Tear down the layer (clear caches on shutdown) + */ + tearDown(): void; + /** + * Get current cache statistics + */ + getStatistics(): { + size: number; + allocCount: number; + derefCount: number; + }; + /** + * IReadLayer implementation - read from cache + */ + read(ids: DocumentID[], options: ChunkReadOptions, next: (remaining: DocumentID[]) => Promise<(EntryLeaf | false)[]>): Promise<(EntryLeaf | false)[]>; + /** + * IWriteLayer implementation - cache chunks after database write + */ + write(chunks: EntryLeaf[], options: ChunkWriteOptions, origin: DocumentID, next: (remaining: EntryLeaf[]) => Promise): Promise; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/ChunkLayerInterfaces.d.ts b/_types/lib/src/managers/LayeredChunkManager/ChunkLayerInterfaces.d.ts new file mode 100644 index 0000000..25cc22d --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/ChunkLayerInterfaces.d.ts @@ -0,0 +1,37 @@ +import type { DocumentID, EntryLeaf } from "@lib/common/models/db.type"; +import type { ChunkReadOptions, ChunkWriteOptions, WriteResult } from "./types.ts"; +/** + * Interface for read layers in the chunk reading pipeline. + * Each layer processes a chunk read request and passes it to the next layer. + */ +export interface IReadLayer { + /** + * Process a read request for the given chunk IDs. + * The next layer in the pipeline should be called to continue processing. + * + * @param ids - The chunk IDs to read + * @param options - Read options + * @param next - The next layer to process the remaining IDs + * @returns A promise that resolves to an array of chunks or false values + */ + read(ids: DocumentID[], options: ChunkReadOptions, next: (remaining: DocumentID[]) => Promise<(EntryLeaf | false)[]>): Promise<(EntryLeaf | false)[]>; + tearDown?(): void; +} +/** + * Interface for write layers in the chunk writing pipeline. + * Each layer processes chunk write requests and passes them to the next layer. + */ +export interface IWriteLayer { + /** + * Process a write request for the given chunks. + * The next layer in the pipeline should be called to continue processing. + * + * @param chunks - The chunks to write + * @param options - Write options + * @param origin - The origin of the write request + * @param next - The next layer to process the remaining chunks + * @returns A promise that resolves to the write result + */ + write(chunks: EntryLeaf[], options: ChunkWriteOptions, origin: DocumentID, next: (remaining: EntryLeaf[]) => Promise): Promise; + tearDown?(): void; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/DatabaseReadLayer.d.ts b/_types/lib/src/managers/LayeredChunkManager/DatabaseReadLayer.d.ts new file mode 100644 index 0000000..5864ff8 --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/DatabaseReadLayer.d.ts @@ -0,0 +1,15 @@ +import type { EntryLeaf, DocumentID } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { IReadLayer } from "./ChunkLayerInterfaces"; +import type { ChunkReadOptions } from "./types.ts"; +/** + * Database read layer - reads chunks from the database + */ +export declare class DatabaseReadLayer implements IReadLayer { + private database; + constructor(database: PouchDB.Database); + private isChunkDoc; + private getError; + private isMissingError; + read(ids: DocumentID[], options: ChunkReadOptions, next: (remaining: DocumentID[]) => Promise<(EntryLeaf | false)[]>): Promise<(EntryLeaf | false)[]>; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/DatabaseWriteLayer.d.ts b/_types/lib/src/managers/LayeredChunkManager/DatabaseWriteLayer.d.ts new file mode 100644 index 0000000..bbee835 --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/DatabaseWriteLayer.d.ts @@ -0,0 +1,12 @@ +import type { EntryLeaf, DocumentID } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { IWriteLayer } from "./ChunkLayerInterfaces"; +import type { ChunkWriteOptions, WriteResult } from "./types.ts"; +/** + * Database write layer - writes chunks to the database + */ +export declare class DatabaseWriteLayer implements IWriteLayer { + private database; + constructor(database: PouchDB.Database); + write(chunks: EntryLeaf[], options: ChunkWriteOptions | undefined, origin: DocumentID, next: (remaining: EntryLeaf[]) => Promise): Promise; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/HotPackLayer.d.ts b/_types/lib/src/managers/LayeredChunkManager/HotPackLayer.d.ts new file mode 100644 index 0000000..d443053 --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/HotPackLayer.d.ts @@ -0,0 +1,9 @@ +import type { EntryLeaf, DocumentID } from "@lib/common/models/db.type"; +import type { IWriteLayer } from "./ChunkLayerInterfaces"; +import type { ChunkWriteOptions, WriteResult } from "./types.ts"; +/** + * Hot pack layer - placeholder for hot pack processing + */ +export declare class HotPackLayer implements IWriteLayer { + write(chunks: EntryLeaf[], options: ChunkWriteOptions, origin: DocumentID, next: (remaining: EntryLeaf[]) => Promise): Promise; +} diff --git a/_types/lib/src/managers/LayeredChunkManager/types.d.ts b/_types/lib/src/managers/LayeredChunkManager/types.d.ts new file mode 100644 index 0000000..3503891 --- /dev/null +++ b/_types/lib/src/managers/LayeredChunkManager/types.d.ts @@ -0,0 +1,33 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { DocumentID, EntryLeaf } from "@lib/common/models/db.type"; +import type { ISettingService } from "@lib/services/base/IService"; +import type { ChangeManager } from "@lib/managers/ChangeManager"; +import type { EVENT_CHUNK_FETCHED, EVENT_MISSING_CHUNK_REMOTE, EVENT_MISSING_CHUNKS } from "@lib/managers/ChunkFetcher"; +export type ChunkManagerOptions = { + database: PouchDB.Database; + changeManager: ChangeManager; + settingService: ISettingService; +}; +export type ChunkReadOptions = { + skipCache?: boolean; + timeout?: number; + preventRemoteRequest?: boolean; +}; +export type ChunkWriteOptions = { + skipCache?: boolean; + force?: boolean; +}; +export type WriteResult = { + result: boolean; + processed: { + cached: number; + hotPack: number; + written: number; + duplicated: number; + }; +}; +export type ChunkManagerEventMap = { + [EVENT_MISSING_CHUNK_REMOTE]: DocumentID; + [EVENT_MISSING_CHUNKS]: DocumentID[]; + [EVENT_CHUNK_FETCHED]: EntryLeaf; +}; diff --git a/_types/lib/src/managers/LiveSyncManagers.d.ts b/_types/lib/src/managers/LiveSyncManagers.d.ts new file mode 100644 index 0000000..8599277 --- /dev/null +++ b/_types/lib/src/managers/LiveSyncManagers.d.ts @@ -0,0 +1,49 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import { ContentSplitter } from "@lib/ContentSplitter/ContentSplitters.ts"; +import { ChangeManager } from "./ChangeManager.ts"; +import { ChunkFetcher } from "./ChunkFetcher.ts"; +import { ChunkManager } from "./ChunkManager.ts"; +import { ConflictManager } from "./ConflictManager.ts"; +import { EntryManager } from "./EntryManager/EntryManager.ts"; +import { HashManager } from "./HashManager/HashManager.ts"; +import type { APIService } from "@lib/services/base/APIService.ts"; +import type { IDatabaseService, IPathService, IReplicatorService, ISettingService } from "@lib/services/base/IService.ts"; +import { type LogFunction } from "@lib/services/lib/logUtils.ts"; +export interface LiveSyncManagersOptions { + database: PouchDB.Database; + databaseService: IDatabaseService; + settingService: TSettingService; + pathService: IPathService; + replicatorService: IReplicatorService; + APIService: APIService; +} +export declare class LiveSyncManagers { + protected _pathService: IPathService; + protected _replicatorService: IReplicatorService; + protected _settingService: ISettingService; + protected _APIService: APIService; + hashManager: HashManager; + chunkFetcher: ChunkFetcher; + changeManager: ChangeManager; + chunkManager: ChunkManager; + splitter: ContentSplitter; + entryManager: EntryManager; + conflictManager: ConflictManager; + protected options: LiveSyncManagersOptions; + protected log: LogFunction; + constructor(options: LiveSyncManagersOptions); + teardownManagers(): Promise; + protected getManagerMembers(): { + changeManager: ChangeManager; + hashManager: HashManager; + splitter: ContentSplitter; + chunkManager: ChunkManager; + chunkFetcher: ChunkFetcher; + entryManager: EntryManager; + conflictManager: ConflictManager; + }; + initialise(): Promise; + reinitialise(): Promise; + clearCaches(): void; + prepareHashFunction(): Promise; +} diff --git a/_types/lib/src/managers/StorageEventManager.d.ts b/_types/lib/src/managers/StorageEventManager.d.ts new file mode 100644 index 0000000..750a51c --- /dev/null +++ b/_types/lib/src/managers/StorageEventManager.d.ts @@ -0,0 +1,136 @@ +import type { FileEventType, UXFileInfoStub, UXFolderInfo, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { FilePath } from "@lib/common/models/db.type"; +import type { FileEventItem } from "@lib/common/models/fileaccess.type"; +import type { IStorageAccessManager } from "@lib/interfaces/StorageAccess.ts"; +import { type PromiseWithResolvers } from "octagonal-wheels/promises"; +import { StorageEventManager, type FileEvent } from "@lib/interfaces/StorageEventManager.ts"; +import type { IAPIService, IVaultService } from "@lib/services/base/IService.ts"; +import type { SettingService } from "@lib/services/base/SettingService.ts"; +import type { FileProcessingService } from "@lib/services/base/FileProcessingService.ts"; +import { createInstanceLogFunction } from "@lib/services/lib/logUtils"; +import type { IStorageEventManagerAdapter } from "./adapters"; +import { type CompatTimeoutHandle } from "@lib/common/coreEnvFunctions"; +type WaitInfo = { + since: number; + type: FileEventType; + canProceed: PromiseWithResolvers; + timerHandler: CompatTimeoutHandle; + event: FileEventItem; +}; +declare const TYPE_SENTINEL_FLUSH = "SENTINEL_FLUSH"; +type FileEventItemSentinelFlush = { + type: typeof TYPE_SENTINEL_FLUSH; +}; +export type FileEventItemSentinel = FileEventItemSentinelFlush; +export interface StorageEventManagerBaseDependencies { + setting: SettingService; + vaultService: IVaultService; + fileProcessing: FileProcessingService; + storageAccessManager: IStorageAccessManager; + APIService: IAPIService; +} +/** + * Type helper to extract the file type from a storage event manager adapter + */ +export type ExtractFile = T extends IStorageEventManagerAdapter ? F : never; +/** + * Type helper to extract the folder type from a storage event manager adapter + */ +export type ExtractFolder = T extends IStorageEventManagerAdapter ? D : never; +/** + * Base class for storage event management + * Uses adapter pattern for platform-specific implementations + * + * @template TAdapter - The storage event manager adapter type + */ +export declare abstract class StorageEventManagerBase> extends StorageEventManager { + _log: ReturnType; + protected setting: SettingService; + protected vaultService: IVaultService; + protected fileProcessing: FileProcessingService; + protected storageAccess: IStorageAccessManager; + protected adapter: TAdapter; + protected get shouldBatchSave(): boolean; + protected get batchSaveMinimumDelay(): number; + protected get batchSaveMaximumDelay(): number; + get settings(): import("../common/types").ObsidianLiveSyncSettings; + constructor(adapter: TAdapter, dependencies: StorageEventManagerBaseDependencies); + _saveSnapshot(snapshot: (FileEventItem | FileEventItemSentinel)[]): Promise; + _loadSnapshot(): Promise<(FileEventItem | FileEventItemSentinel)[] | null>; + isFolder(file: UXFileInfoStub | UXInternalFileInfoStub | UXFolderInfo | ExtractFolder | ExtractFile): boolean; + isFile(file: UXFileInfoStub | UXInternalFileInfoStub | UXFolderInfo | ExtractFolder | ExtractFile): boolean; + protected updateStatus(): void; + /** + * Snapshot restoration promise. + * Snapshot will be restored before starting to watch vault changes. + * In designed time, this has been called from Initialisation process, which has been implemented on `ModuleInitializerFile.ts`. + */ + snapShotRestored: Promise | null; + /** + * Restore the previous snapshot if exists. + * @returns + */ + restoreState(): Promise; + appendQueue(params: FileEvent[], ctx?: unknown): Promise; + protected bufferedQueuedItems: (FileEventItem | FileEventItemSentinel)[]; + enqueue(newItem: FileEventItem): void; + /** + * Immediately take snapshot. + */ + private _triggerTakeSnapshot; + /** + * Trigger taking snapshot after throttled period. + */ + triggerTakeSnapshot: import("octagonal-wheels/function").ThrottledFunction<() => void>; + protected concurrentProcessing: import("octagonal-wheels/concurrency/semaphore_v2").SemaphoreObject; + protected _waitingMap: Map; + private _waitForIdle; + /** + * Wait until all queued events are processed. + * Subsequent new events will not be waited, but new events will not be added. + * @returns + */ + waitForIdle(): Promise; + /** + * Proceed waiting for the given key immediately. + */ + private _proceedWaiting; + /** + * Cancel waiting for the given key. + */ + private _cancelWaiting; + /** + * Add waiting for the given key. + * @param key + * @param event + * @param waitedSince Optional waited since timestamp to calculate the remaining delay. + */ + private _addWaiting; + /** + * Process the given file event. + */ + processFileEvent(fei: FileEventItem): Promise; + _takeSnapshot(): Promise; + _restoreFromSnapshot(): Promise; + protected runQueuedEvents(): Promise; + protected processingCount: number; + protected requestProcessQueue(fei: FileEventItem): Promise; + isWaiting(filename: FilePath): boolean; + protected handleFileEvent(queue: FileEventItem): Promise; + protected cancelRelativeEvent(item: FileEventItem): void; + /** + * Begin watching for storage events + */ + beginWatch(): Promise; + /** + * Platform-agnostic event handlers + */ + protected watchEditorChange(editor: any, info: any): void; + protected watchVaultCreate(file: any, ctx?: any): void; + protected watchVaultChange(file: any, ctx?: any): void; + protected watchVaultDelete(file: any, ctx?: any): void; + protected watchVaultRename(file: any, oldPath: string, ctx?: any): void; + protected watchVaultRawEvents(path: FilePath): void; + protected _watchVaultRawEvents(path: FilePath): Promise; +} +export {}; diff --git a/_types/lib/src/managers/StorageProcessingManager.d.ts b/_types/lib/src/managers/StorageProcessingManager.d.ts new file mode 100644 index 0000000..4dddf1d --- /dev/null +++ b/_types/lib/src/managers/StorageProcessingManager.d.ts @@ -0,0 +1,14 @@ +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { IStorageAccessManager } from "@lib/interfaces/StorageAccess"; +import type { FileWithFileStat, FileWithStatAsProp } from "@lib/common/models/fileaccess.type"; +export declare class StorageAccessManager implements IStorageAccessManager { + processingFiles: Set; + processWriteFile(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise): Promise; + processReadFile(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise): Promise; + isFileProcessing(file: UXFileInfoStub | FilePathWithPrefix): boolean; + private touchedFiles; + touch(file: FileWithFileStat | FileWithStatAsProp): void; + recentlyTouched(file: FileWithStatAsProp | FileWithFileStat): boolean; + clearTouched(): void; +} diff --git a/_types/lib/src/managers/adapters/IStorageEventConverterAdapter.d.ts b/_types/lib/src/managers/adapters/IStorageEventConverterAdapter.d.ts new file mode 100644 index 0000000..31d768c --- /dev/null +++ b/_types/lib/src/managers/adapters/IStorageEventConverterAdapter.d.ts @@ -0,0 +1,17 @@ +import type { FilePath } from "@lib/common/models/db.type"; +import type { UXFileInfoStub, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +/** + * Adapter interface for converting platform-specific file types to UX types + * + * @template TFile - Platform-specific file type + */ +export interface IStorageEventConverterAdapter { + /** + * Convert platform-specific file to UXFileInfoStub + */ + toFileInfo(file: TFile, deleted?: boolean): UXFileInfoStub; + /** + * Convert path to UXInternalFileInfoStub + */ + toInternalFileInfo(path: FilePath): UXInternalFileInfoStub; +} diff --git a/_types/lib/src/managers/adapters/IStorageEventManagerAdapter.d.ts b/_types/lib/src/managers/adapters/IStorageEventManagerAdapter.d.ts new file mode 100644 index 0000000..a55a3a0 --- /dev/null +++ b/_types/lib/src/managers/adapters/IStorageEventManagerAdapter.d.ts @@ -0,0 +1,18 @@ +import type { IStorageEventTypeGuardAdapter } from "./IStorageEventTypeGuardAdapter"; +import type { IStorageEventPersistenceAdapter } from "./IStorageEventPersistenceAdapter"; +import type { IStorageEventWatchAdapter } from "./IStorageEventWatchAdapter"; +import type { IStorageEventStatusAdapter } from "./IStorageEventStatusAdapter"; +import type { IStorageEventConverterAdapter } from "./IStorageEventConverterAdapter"; +/** + * Composite adapter interface for StorageEventManager + * + * @template TFile - Platform-specific file type + * @template TFolder - Platform-specific folder type + */ +export interface IStorageEventManagerAdapter { + readonly typeGuard: IStorageEventTypeGuardAdapter; + readonly persistence: IStorageEventPersistenceAdapter; + readonly watch: IStorageEventWatchAdapter; + readonly status: IStorageEventStatusAdapter; + readonly converter: IStorageEventConverterAdapter; +} diff --git a/_types/lib/src/managers/adapters/IStorageEventPersistenceAdapter.d.ts b/_types/lib/src/managers/adapters/IStorageEventPersistenceAdapter.d.ts new file mode 100644 index 0000000..6570588 --- /dev/null +++ b/_types/lib/src/managers/adapters/IStorageEventPersistenceAdapter.d.ts @@ -0,0 +1,15 @@ +import type { FileEventItem } from "@lib/common/models/fileaccess.type"; +import type { FileEventItemSentinel } from "@lib/managers/StorageEventManager"; +/** + * Adapter interface for snapshot persistence operations + */ +export interface IStorageEventPersistenceAdapter { + /** + * Save the snapshot of pending events + */ + saveSnapshot(snapshot: (FileEventItem | FileEventItemSentinel)[]): Promise; + /** + * Load the snapshot of pending events + */ + loadSnapshot(): Promise<(FileEventItem | FileEventItemSentinel)[] | null>; +} diff --git a/_types/lib/src/managers/adapters/IStorageEventStatusAdapter.d.ts b/_types/lib/src/managers/adapters/IStorageEventStatusAdapter.d.ts new file mode 100644 index 0000000..a9b7931 --- /dev/null +++ b/_types/lib/src/managers/adapters/IStorageEventStatusAdapter.d.ts @@ -0,0 +1,13 @@ +/** + * Adapter interface for status update operations + */ +export interface IStorageEventStatusAdapter { + /** + * Update the status display + */ + updateStatus(status: { + batched: number; + processing: number; + totalQueued: number; + }): void; +} diff --git a/_types/lib/src/managers/adapters/IStorageEventTypeGuardAdapter.d.ts b/_types/lib/src/managers/adapters/IStorageEventTypeGuardAdapter.d.ts new file mode 100644 index 0000000..a9a13a0 --- /dev/null +++ b/_types/lib/src/managers/adapters/IStorageEventTypeGuardAdapter.d.ts @@ -0,0 +1,16 @@ +/** + * Adapter interface for type guard operations in StorageEventManager + * + * @template TFile - Platform-specific file type + * @template TFolder - Platform-specific folder type + */ +export interface IStorageEventTypeGuardAdapter { + /** + * Check if the given item is a file + */ + isFile(file: unknown): file is TFile; + /** + * Check if the given item is a folder + */ + isFolder(item: unknown): item is TFolder; +} diff --git a/_types/lib/src/managers/adapters/IStorageEventWatchAdapter.d.ts b/_types/lib/src/managers/adapters/IStorageEventWatchAdapter.d.ts new file mode 100644 index 0000000..382a667 --- /dev/null +++ b/_types/lib/src/managers/adapters/IStorageEventWatchAdapter.d.ts @@ -0,0 +1,21 @@ +import type { FilePath } from "@lib/common/models/db.type"; +/** + * Event handlers for storage events + */ +export interface IStorageEventWatchHandlers { + onCreate: (file: unknown, ctx?: unknown) => void; + onChange: (file: unknown, ctx?: unknown) => void; + onDelete: (file: unknown, ctx?: unknown) => void; + onRename: (file: unknown, oldPath: string, ctx?: unknown) => void; + onRaw: (path: FilePath) => void; + onEditorChange?: (editor: unknown, info: unknown) => void; +} +/** + * Adapter interface for watching vault/storage events + */ +export interface IStorageEventWatchAdapter { + /** + * Begin watching for storage events + */ + beginWatch(handlers: IStorageEventWatchHandlers): Promise; +} diff --git a/_types/lib/src/managers/adapters/index.d.ts b/_types/lib/src/managers/adapters/index.d.ts new file mode 100644 index 0000000..4841547 --- /dev/null +++ b/_types/lib/src/managers/adapters/index.d.ts @@ -0,0 +1,6 @@ +export type { IStorageEventTypeGuardAdapter } from "./IStorageEventTypeGuardAdapter"; +export type { IStorageEventPersistenceAdapter } from "./IStorageEventPersistenceAdapter"; +export type { IStorageEventWatchAdapter, IStorageEventWatchHandlers } from "./IStorageEventWatchAdapter"; +export type { IStorageEventStatusAdapter } from "./IStorageEventStatusAdapter"; +export type { IStorageEventConverterAdapter } from "./IStorageEventConverterAdapter"; +export type { IStorageEventManagerAdapter } from "./IStorageEventManagerAdapter"; diff --git a/_types/lib/src/mock_and_interop/stores.d.ts b/_types/lib/src/mock_and_interop/stores.d.ts new file mode 100644 index 0000000..804c34f --- /dev/null +++ b/_types/lib/src/mock_and_interop/stores.d.ts @@ -0,0 +1,21 @@ +import type { LOG_LEVEL } from "@lib/common/logger"; +export type LockStats = { + pending: string[]; + running: string[]; + count: number; +}; +export declare const lockStats: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource<{ + pending: never[]; + running: never[]; + count: number; +}>; +export declare const collectingChunks: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +export declare const pluginScanningCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +export declare const hiddenFilesProcessingCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +export declare const hiddenFilesEventCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +export type LogEntry = { + message: string | Error; + level?: LOG_LEVEL; + key?: string; +}; +export declare const logMessages: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; diff --git a/_types/lib/src/mock_and_interop/wrapper.d.ts b/_types/lib/src/mock_and_interop/wrapper.d.ts new file mode 100644 index 0000000..6e94097 --- /dev/null +++ b/_types/lib/src/mock_and_interop/wrapper.d.ts @@ -0,0 +1,7 @@ +export declare class WrappedNotice { + constructor(message: string | DocumentFragment, timeout?: number); + setMessage(message: string | DocumentFragment): this; + hide(): void; +} +export declare function setNoticeClass(notice: typeof WrappedNotice): void; +export declare function NewNotice(message: string | DocumentFragment, timeout?: number): WrappedNotice; diff --git a/_types/lib/src/mods.d.ts b/_types/lib/src/mods.d.ts new file mode 100644 index 0000000..28f2afa --- /dev/null +++ b/_types/lib/src/mods.d.ts @@ -0,0 +1 @@ +export declare function getWebCrypto(): Promise; diff --git a/_types/lib/src/pouchdb/LiveSyncDBFunctions.d.ts b/_types/lib/src/pouchdb/LiveSyncDBFunctions.d.ts new file mode 100644 index 0000000..5dcb1b5 --- /dev/null +++ b/_types/lib/src/pouchdb/LiveSyncDBFunctions.d.ts @@ -0,0 +1,17 @@ +import type { EntryDoc, EntryMilestoneInfo, DeviceInfo } from "@lib/common/models/db.definition"; +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { ChunkVersionRange } from "@lib/common/models/db.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +export type ENSURE_DB_RESULT = "OK" | "INCOMPATIBLE" | "LOCKED" | "NODE_LOCKED" | "NODE_CLEANED" | ["MISMATCHED", TweakValues]; +/** + * Ensures that the remote database is compatible with the current device. + * + * @param infoSrc - The information about the remote database (which retrieved from the remote). + * @param setting - The current settings. + * @param deviceNodeID - The ID of the current device node. + * @param currentVersionRange - The current version range of the database. + * @param updateCallback - The callback function to update the remote milestone. + * @returns A promise that resolves to the result of ensuring compatibility. + */ +export declare function ensureRemoteIsCompatible(infoSrc: EntryMilestoneInfo | false, setting: RemoteDBSettings, deviceNodeID: string, currentVersionRange: ChunkVersionRange, nodeDeviceInfo: DeviceInfo, updateCallback: (info: EntryMilestoneInfo) => Promise): Promise; +export declare function ensureDatabaseIsCompatible(db: PouchDB.Database, setting: RemoteDBSettings, deviceNodeID: string, currentVersionRange: ChunkVersionRange, nodeDeviceInfo: DeviceInfo): Promise; diff --git a/_types/lib/src/pouchdb/LiveSyncLocalDB.d.ts b/_types/lib/src/pouchdb/LiveSyncLocalDB.d.ts new file mode 100644 index 0000000..0c23050 --- /dev/null +++ b/_types/lib/src/pouchdb/LiveSyncLocalDB.d.ts @@ -0,0 +1,98 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { EntryLeaf, DocumentID, FilePathWithPrefix, FilePath, DatabaseEntry, LoadedEntry, MetaEntry, SavingEntry } from "@lib/common/models/db.type"; +import type { Credential } from "@lib/common/models/auth.type"; +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { diff_result_leaf } from "@lib/common/models/diff.definition"; +import { eventHub } from "@lib/hub/hub.ts"; +import { LiveSyncManagers } from "@lib/managers/LiveSyncManagers.ts"; +import type { AutoMergeResult } from "@lib/managers/ConflictManager.ts"; +import type { IServiceHub } from "@lib/services/base/IService.ts"; +import { type LogFunction } from "@lib/services/lib/logUtils.ts"; +export declare const REMOTE_CHUNK_FETCHED = "remote-chunk-fetched"; +export type REMOTE_CHUNK_FETCHED = typeof REMOTE_CHUNK_FETCHED; +declare global { + interface LSEvents { + [REMOTE_CHUNK_FETCHED]: EntryLeaf; + } +} +export type ChunkRetrievalResultSuccess = { + _id: DocumentID; + data: string; + type: "leaf"; +}; +export type ChunkRetrievalResultError = { + _id: DocumentID; + error: string; +}; +export type ChunkRetrievalResult = ChunkRetrievalResultSuccess | ChunkRetrievalResultError; +export interface LiveSyncLocalDBEnv { + services: Pick; +} +export declare function getNoFromRev(rev: string): number; +export type GeneratedChunk = { + isNew: boolean; + id: DocumentID; + piece: string; +}; +export declare class LiveSyncLocalDB { + auth: Credential; + dbname: string; + settings: RemoteDBSettings; + localDatabase: PouchDB.Database; + _log: LogFunction; + private _managers?; + get managers(): LiveSyncManagers; + isReady: boolean; + needScanning: boolean; + env: LiveSyncLocalDBEnv; + clearCaches(): void; + _prepareHashFunctions(): Promise; + onunload(): void; + refreshSettings(): void; + offRemoteChunkFetchedHandler?: ReturnType; + constructor(dbname: string, env: LiveSyncLocalDBEnv); + close(): Promise; + onNewLeaf(chunk: EntryLeaf): void; + initializeDatabase(): Promise; + /** + * Retrieve all used and existing chunks in the database. + * @param includeDeleted include deleted chunks in the result. + * @returns {used: Set, existing: Map} used: Set of chunk ids that are used in the database. existing: Map of chunk id and EntryLeaf that are existing in the database. + */ + allChunks(includeDeleted?: boolean): Promise<{ + used: Set; + existing: Map; + }>; + resetDatabase(): Promise; + findEntries(startKey: string, endKey: string, opt: PouchDB.Core.AllDocsWithKeyOptions | PouchDB.Core.AllDocsOptions | PouchDB.Core.AllDocsWithKeysOptions | PouchDB.Core.AllDocsWithinRangeOptions): AsyncGenerator<(import("@lib/common/models/db.type").NewEntry & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").PlainEntry & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").NewEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; + } & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").PlainEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; + } & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta), void, unknown>; + findAllDocs(opt?: PouchDB.Core.AllDocsWithKeyOptions | PouchDB.Core.AllDocsOptions | PouchDB.Core.AllDocsWithKeysOptions | PouchDB.Core.AllDocsWithinRangeOptions): AsyncGenerator<(import("@lib/common/models/db.type").NewEntry & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").PlainEntry & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").NewEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; + } & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").PlainEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; + } & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta), void, unknown>; + findEntryNames(startKey: string, endKey: string, opt: PouchDB.Core.AllDocsWithKeyOptions | PouchDB.Core.AllDocsOptions | PouchDB.Core.AllDocsWithKeysOptions | PouchDB.Core.AllDocsWithinRangeOptions): AsyncGenerator; + findAllDocNames(opt?: PouchDB.Core.AllDocsWithKeyOptions | PouchDB.Core.AllDocsOptions | PouchDB.Core.AllDocsWithKeysOptions | PouchDB.Core.AllDocsWithinRangeOptions): AsyncGenerator; + findAllNormalDocs(opt?: PouchDB.Core.AllDocsWithKeyOptions | PouchDB.Core.AllDocsOptions | PouchDB.Core.AllDocsWithKeysOptions | PouchDB.Core.AllDocsWithinRangeOptions): AsyncGenerator<(import("@lib/common/models/db.type").NewEntry & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").PlainEntry & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").NewEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; + } & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta) | (import("@lib/common/models/db.type").PlainEntry & import("@lib/common/models/db.type").EntryWithBody & { + datatype: import("@lib/common/models/db.type").EntryTypeNotes; + } & PouchDB.Core.AllDocsMeta & PouchDB.Core.IdMeta & PouchDB.Core.RevisionIdMeta), void, unknown>; + removeRevision(docId: DocumentID, revision: string): Promise; + getRaw(docId: DocumentID, options?: PouchDB.Core.GetOptions): Promise; + removeRaw(docId: DocumentID, revision: string, options?: PouchDB.Core.Options): Promise; + putRaw(doc: T, options?: PouchDB.Core.PutOptions): Promise; + allDocsRaw(options?: PouchDB.Core.AllDocsWithKeyOptions | PouchDB.Core.AllDocsWithKeysOptions | PouchDB.Core.AllDocsWithinRangeOptions | PouchDB.Core.AllDocsOptions): Promise>; + bulkDocsRaw(docs: Array>, options?: PouchDB.Core.BulkDocsOptions): Promise>; + isTargetFile(filenameSrc: string): boolean; + getDBEntryMeta(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, includeDeleted?: boolean): Promise; + getDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, dump?: boolean, waitForReady?: boolean, includeDeleted?: boolean): Promise; + getDBEntryFromMeta(meta: LoadedEntry | MetaEntry, dump?: boolean, waitForReady?: boolean): Promise; + deleteDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions): Promise; + putDBEntry(note: SavingEntry, onlyChunks?: boolean, conflictBaseRev?: string): Promise; + getConflictedDoc(path: FilePathWithPrefix, rev: string): Promise; + tryAutoMerge(path: FilePathWithPrefix, enableMarkdownAutoMerge: boolean): AutoMergeResult; +} diff --git a/_types/lib/src/pouchdb/ReplicatorShim.d.ts b/_types/lib/src/pouchdb/ReplicatorShim.d.ts new file mode 100644 index 0000000..a947434 --- /dev/null +++ b/_types/lib/src/pouchdb/ReplicatorShim.d.ts @@ -0,0 +1,51 @@ +export type SomeDocument = PouchDB.Core.ExistingDocument & PouchDB.Core.ChangesMeta; +/** + * Minimal subset of the PouchDB public API required by {@link replicateShim}. + * Both a real `PouchDB.Database` and an {@link RpcPouchDBProxy} satisfy this + * interface, allowing replication across an RPC transport. + */ +export type PouchDBShim = { + info: () => Promise; + changes: (options: PouchDB.Core.ChangesOptions) => PromiseLike>; + revsDiff: (diff: PouchDB.Core.RevisionDiffOptions) => Promise; + bulkDocs: (docs: PouchDB.Core.PostDocument[], options?: PouchDB.Core.BulkDocsOptions) => Promise<(PouchDB.Core.Response | PouchDB.Core.Error)[]>; + bulkGet: (options: PouchDB.Core.BulkGetOptions) => Promise>; + put: (doc: PouchDB.Core.PutDocument, options?: PouchDB.Core.PutOptions) => Promise; + get: (id: string, options?: PouchDB.Core.GetOptions) => Promise; +}; +type CompatibleDatabase = PouchDB.Database> | PouchDBShim>; +/** Upserts a document by `id`, calling `func` to produce the updated version. */ +export declare function upsert = SomeDocument>(db: CompatibleDatabase, id: string, func: (doc: T) => T): Promise; +export type ShimReplicationOptionBase = { + rewind?: boolean; + batch_size?: number; +}; +export type ShimReplicationOneShot = { + live?: false; + controller?: AbortController; +} & ShimReplicationOptionBase; +export type ShimReplicationOptionContinuous = { + live: true; + controller: AbortController; +} & ShimReplicationOptionBase; +export type ShimReplicationOption = ShimReplicationOneShot | ShimReplicationOptionContinuous; +export type ProgressInfo = { + lastSeq: number; + maxSeqInBatch: number; +}; +export type ShimReplicationProgressReportFunc = (progress: SomeDocument[], progressInfo: ProgressInfo) => Promise; +/** + * Replicate documents from `sourceDB` into `targetDB` using a CouchDB-style + * checkpoint protocol. + * + * Both parameters accept either a real `PouchDB.Database` or any object + * implementing {@link PouchDBShim} — including {@link RpcPouchDBProxy} — so + * replication can span an RPC transport boundary. + * + * @param targetDB Destination database (usually local). + * @param sourceDB Source database (may be remote / RPC-backed). + * @param progress Called after each batch with the written documents. + * @param option Replication options (live mode, batch size, abort signal). + */ +export declare function replicateShim, U extends CompatibleDatabase, V extends object>(targetDB: T, sourceDB: U, progress: ShimReplicationProgressReportFunc, option?: ShimReplicationOption): Promise; +export {}; diff --git a/_types/lib/src/pouchdb/StreamingFetch.d.ts b/_types/lib/src/pouchdb/StreamingFetch.d.ts new file mode 100644 index 0000000..c04cc30 --- /dev/null +++ b/_types/lib/src/pouchdb/StreamingFetch.d.ts @@ -0,0 +1,17 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { AnyEntry, EntryLeaf } from "@lib/common/models/db.type"; +export type FetchChangesForInitialSyncProgress = { + totalFetched: number; + totalValidFetched: number; + targetSeq: number | string; + docsToFetch: number; + totalBytes: number; +}; +/** + * Fetches initial data from CouchDB as a stream and writes it into PouchDB. + * @param downloadToDB PouchDB instance. + * @param remoteDbUrl CouchDB database URL (for example: 'https://xxx.com/mydb'). + * @param decryptFunction Function to decrypt each document. + * @param since Sequence ID to start fetching changes from (default is '0'). + */ +export declare function fetchChangesForInitialSync(downloadToDB: PouchDB.Database, remoteDbUrl: string, authHeader: string, decryptFunction: (doc: EntryDoc) => Promise, since?: number | string, onProgress?: (progress: FetchChangesForInitialSyncProgress) => void): Promise; diff --git a/_types/lib/src/pouchdb/chunks.d.ts b/_types/lib/src/pouchdb/chunks.d.ts new file mode 100644 index 0000000..a54c427 --- /dev/null +++ b/_types/lib/src/pouchdb/chunks.d.ts @@ -0,0 +1,38 @@ +import type { CouchDBConnection } from "@lib/common/models/setting.type"; +export declare function purgeUnreferencedChunks(db: PouchDB.Database, dryRun: boolean, connSetting?: CouchDBConnection, performCompact?: boolean): Promise; +export declare function transferChunks(key: string, label: string, dbFrom: PouchDB.Database, dbTo: PouchDB.Database, items: { + id: string; + rev: string; +}[]): Promise; +export declare function balanceChunkPurgedDBs(local: PouchDB.Database, remote: PouchDB.Database): Promise; +export declare function fetchAllUsedChunks(local: PouchDB.Database, remote: PouchDB.Database): Promise; +export declare function purgeChunksLocal(db: PouchDB.Database, docs: { + id: string; + rev: string; +}[]): Promise; +export declare function collectUnbalancedChunkIDs(local: PouchDB.Database, remote: PouchDB.Database): Promise<{ + onlyOnLocal: { + id: string; + rev: string; + }[]; + onlyOnRemote: { + id: string; + rev: string; + }[]; +}>; +export declare function collectChunks(db: PouchDB.Database, type: "INUSE" | "DANGLING" | "ALL"): Promise<{ + id: string; + rev: string; +}[]>; +export declare function collectChunksUsage(db: PouchDB.Database): Promise<{ + value: number; + key: string[]; +}[]>; +export declare function collectUnreferencedChunks(db: PouchDB.Database): Promise<{ + id: string; + rev: string; +}[]>; +export declare function purgeChunksRemote(setting: CouchDBConnection, docs: { + id: string; + rev: string; +}[]): Promise; diff --git a/_types/lib/src/pouchdb/compress.d.ts b/_types/lib/src/pouchdb/compress.d.ts new file mode 100644 index 0000000..e4a96fe --- /dev/null +++ b/_types/lib/src/pouchdb/compress.d.ts @@ -0,0 +1,11 @@ +import * as fflate from "fflate"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +export declare function _compressText(text: string): Promise; +export declare const wrappedInflate: (data: Uint8Array, opts: fflate.AsyncInflateOptions) => Promise>; +export declare const wrappedDeflate: (data: Uint8Array, opts: fflate.AsyncDeflateOptions) => Promise>; +export declare function _decompressText(compressed: string, _useUTF16?: boolean): Promise; +export declare function compressDoc(doc: EntryDoc): Promise; +export declare function decompressDoc(doc: EntryDoc): Promise; +export declare function wrapFflateFunc(func: (data: T, opts: U, cb: fflate.FlateCallback) => any): (data: T, opts: U) => Promise>; +export declare const replicationFilter: (db: PouchDB.Database, compress: boolean) => void; +export declare const MARK_SHIFT_COMPRESSED = "\u000ELZ\u001D"; diff --git a/_types/lib/src/pouchdb/encryption.d.ts b/_types/lib/src/pouchdb/encryption.d.ts new file mode 100644 index 0000000..91993f6 --- /dev/null +++ b/_types/lib/src/pouchdb/encryption.d.ts @@ -0,0 +1,22 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { AnyEntry, EntryLeaf, DocumentID } from "@lib/common/models/db.type"; +import type { E2EEAlgorithm } from "@lib/common/models/setting.type"; +import { encryptWorker, decryptWorker, encryptHKDFWorker, decryptHKDFWorker } from "@lib/worker/bgWorker.ts"; +export declare const encrypt: typeof encryptWorker; +export declare const decrypt: typeof decryptWorker; +export declare const encryptHKDF: typeof encryptHKDFWorker; +export declare const decryptHKDF: typeof decryptHKDFWorker; +export declare let preprocessOutgoing: (doc: AnyEntry | EntryLeaf) => Promise; +export declare let preprocessIncoming: (doc: EntryDoc) => Promise; +export declare function getConfiguredFunctionsForEncryption(passphrase: string, useDynamicIterationCount: boolean, migrationDecrypt: boolean, getPBKDF2Salt: () => Promise>, algorithm: E2EEAlgorithm): { + incoming: (doc: AnyEntry | EntryLeaf) => Promise; + outgoing: (doc: EntryDoc) => Promise; +}; +export declare const enableEncryption: (db: PouchDB.Database, passphrase: string, useDynamicIterationCount: boolean, migrationDecrypt: boolean, getPBKDF2Salt: () => Promise>, algorithm: E2EEAlgorithm) => void; +export declare function disableEncryption(): void; +export declare const EDEN_ENCRYPTED_KEY: DocumentID; +export declare const EDEN_ENCRYPTED_KEY_HKDF: DocumentID; +export declare function shouldEncryptEden(doc: AnyEntry | EntryLeaf): doc is AnyEntry; +export declare function shouldEncryptEdenHKDF(doc: AnyEntry | EntryLeaf): doc is AnyEntry; +export declare function shouldDecryptEden(doc: AnyEntry | EntryLeaf): doc is AnyEntry; +export declare function shouldDecryptEdenHKDF(doc: AnyEntry | EntryLeaf): doc is AnyEntry; diff --git a/_types/lib/src/pouchdb/negotiation.d.ts b/_types/lib/src/pouchdb/negotiation.d.ts new file mode 100644 index 0000000..a460017 --- /dev/null +++ b/_types/lib/src/pouchdb/negotiation.d.ts @@ -0,0 +1,9 @@ +export declare const checkRemoteVersion: (db: PouchDB.Database, migrate: (from: number, to: number) => Promise, barrier?: number) => Promise; +export declare const bumpRemoteVersion: (db: PouchDB.Database, barrier?: number) => Promise; +export declare const checkSyncInfo: (db: PouchDB.Database) => Promise; +/** + * Counts the number of remote (potentially) compromised chunks in the database. + * @param db The PouchDB database instance. + * @returns The number of compromised chunks or false if an error occurs. + */ +export declare function countCompromisedChunks(db: PouchDB.Database): Promise; diff --git a/_types/lib/src/pouchdb/pouchdb-browser.d.ts b/_types/lib/src/pouchdb/pouchdb-browser.d.ts new file mode 100644 index 0000000..40fefb6 --- /dev/null +++ b/_types/lib/src/pouchdb/pouchdb-browser.d.ts @@ -0,0 +1,2 @@ +import PouchDB from "pouchdb-core"; +export { PouchDB }; diff --git a/_types/lib/src/pouchdb/pouchdb-http.d.ts b/_types/lib/src/pouchdb/pouchdb-http.d.ts new file mode 100644 index 0000000..40fefb6 --- /dev/null +++ b/_types/lib/src/pouchdb/pouchdb-http.d.ts @@ -0,0 +1,2 @@ +import PouchDB from "pouchdb-core"; +export { PouchDB }; diff --git a/_types/lib/src/pouchdb/pouchdb-test.d.ts b/_types/lib/src/pouchdb/pouchdb-test.d.ts new file mode 100644 index 0000000..40fefb6 --- /dev/null +++ b/_types/lib/src/pouchdb/pouchdb-test.d.ts @@ -0,0 +1,2 @@ +import PouchDB from "pouchdb-core"; +export { PouchDB }; diff --git a/_types/lib/src/pouchdb/utils_couchdb.d.ts b/_types/lib/src/pouchdb/utils_couchdb.d.ts new file mode 100644 index 0000000..e138599 --- /dev/null +++ b/_types/lib/src/pouchdb/utils_couchdb.d.ts @@ -0,0 +1,4 @@ +export declare const isValidRemoteCouchDBURI: (uri: string) => boolean; +export declare function isCloudantURI(uri: string): boolean; +export declare function isErrorOfMissingDoc(ex: unknown): boolean; +export declare const _requestToCouchDBFetch: (baseUri: string, username: string, password: string, path?: string, body?: unknown, method?: string) => Promise; diff --git a/_types/lib/src/replication/LiveSyncAbstractReplicator.d.ts b/_types/lib/src/replication/LiveSyncAbstractReplicator.d.ts new file mode 100644 index 0000000..0eb2f1e --- /dev/null +++ b/_types/lib/src/replication/LiveSyncAbstractReplicator.d.ts @@ -0,0 +1,71 @@ +import type { EntryDoc, NodeData } from "@lib/common/models/db.definition"; +import type { DatabaseConnectingStatus } from "@lib/common/models/shared.definition"; +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { EntryLeaf } from "@lib/common/models/db.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import type { IServiceHub } from "@lib/services/base/IService.ts"; +export type ReplicationCallback = (e: PouchDB.Core.ExistingDocument[]) => Promise | boolean; +export type ReplicationStat = { + sent: number; + arrived: number; + maxPullSeq: number; + maxPushSeq: number; + lastSyncPullSeq: number; + lastSyncPushSeq: number; + syncStatus: DatabaseConnectingStatus; +}; +export interface LiveSyncReplicatorEnv { + services: IServiceHub; +} +export type RemoteDBStatus = { + [key: string]: unknown; + estimatedSize?: number; +}; +export declare abstract class LiveSyncAbstractReplicator { + syncStatus: DatabaseConnectingStatus; + docArrived: number; + docSent: number; + lastSyncPullSeq: number; + maxPullSeq: number; + lastSyncPushSeq: number; + maxPushSeq: number; + controller?: AbortController; + originalSetting: RemoteDBSettings; + nodeid: string; + remoteLocked: boolean; + remoteCleaned: boolean; + remoteLockedAndDeviceNotAccepted: boolean; + tweakSettingsMismatched: boolean; + preferredTweakValue?: TweakValues; + abstract get isChunkSendingSupported(): boolean; + get database(): import("../pouchdb/LiveSyncLocalDB").LiveSyncLocalDB; + get rawDatabase(): PouchDB.Database; + get currentSettings(): import("@lib/common/models/setting.type").ObsidianLiveSyncSettings; + sendChunks(setting: RemoteDBSettings, remoteDB: PouchDB.Database | undefined, showResult: boolean, fromSeq?: number | string): Promise; + abstract getReplicationPBKDF2Salt(setting: RemoteDBSettings, refresh?: boolean): Promise>; + ensurePBKDF2Salt(setting: RemoteDBSettings, showMessage?: boolean, useCache?: boolean): Promise; + env: LiveSyncReplicatorEnv; + initializeDatabaseForReplication(): Promise; + constructor(env: LiveSyncReplicatorEnv); + abstract terminateSync(): void; + abstract openReplication(setting: RemoteDBSettings, keepAlive: boolean, showResult: boolean, ignoreCleanLock: boolean): Promise; + updateInfo: () => void; + abstract tryConnectRemote(setting: RemoteDBSettings, showResult?: boolean): Promise; + abstract replicateAllToServer(setting: RemoteDBSettings, showingNotice?: boolean, sendChunksInBulkDisabled?: boolean): Promise; + abstract replicateAllFromServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise; + abstract closeReplication(): void; + abstract tryResetRemoteDatabase(setting: RemoteDBSettings): Promise; + abstract tryCreateRemoteDatabase(setting: RemoteDBSettings): Promise; + abstract markRemoteLocked(setting: RemoteDBSettings, locked: boolean, lockByClean: boolean): Promise; + abstract markRemoteResolved(setting: RemoteDBSettings): Promise; + abstract resetRemoteTweakSettings(setting: RemoteDBSettings): Promise; + abstract setPreferredRemoteTweakSettings(setting: RemoteDBSettings): Promise; + abstract fetchRemoteChunks(missingChunks: string[], showResult: boolean): Promise; + abstract getRemoteStatus(setting: RemoteDBSettings): Promise; + abstract getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise; + abstract countCompromisedChunks(setting?: RemoteDBSettings): Promise; + abstract getConnectedDeviceList(setting?: RemoteDBSettings): Promise; + accepted_nodes: string[]; + }>; +} diff --git a/_types/lib/src/replication/SyncParamsHandler.d.ts b/_types/lib/src/replication/SyncParamsHandler.d.ts new file mode 100644 index 0000000..05664c5 --- /dev/null +++ b/_types/lib/src/replication/SyncParamsHandler.d.ts @@ -0,0 +1,35 @@ +import type { SyncParameters } from "@lib/common/models/sync.definition"; +import { LiveSyncError } from "@lib/common/LSError.ts"; +/** + * Creates a SyncParamsHandler for managing synchronisation parameters. + */ +type putFunc = (params: SyncParameters) => Promise; +/** + * Fetches synchronisation parameters from the server. + */ +type getFunc = () => Promise; +/** + * The function to create new synchronisation parameters. + * Note that this function should not return `pbkdf2salt` in the result; it should be generated and stored in the handler. + */ +type createFunc = () => Promise; +type CreateSyncParamsHanderOptions = { + put: putFunc; + get: getFunc; + create: createFunc; +}; +export type SyncParamsHandler = { + fetch: (refresh?: boolean) => Promise; + getPBKDF2Salt: (refresh?: boolean) => Promise>; +}; +export declare function createSyncParamsHanderForServer(key: string, options: CreateSyncParamsHanderOptions): SyncParamsHandler; +export declare function clearHandlers(): void; +export declare class SyncParamsHandlerError extends LiveSyncError { +} +export declare class SyncParamsFetchError extends SyncParamsHandlerError { +} +export declare class SyncParamsNotFoundError extends SyncParamsHandlerError { +} +export declare class SyncParamsUpdateError extends SyncParamsHandlerError { +} +export {}; diff --git a/_types/lib/src/replication/couchdb/LiveSyncReplicator.d.ts b/_types/lib/src/replication/couchdb/LiveSyncReplicator.d.ts new file mode 100644 index 0000000..bde0f34 --- /dev/null +++ b/_types/lib/src/replication/couchdb/LiveSyncReplicator.d.ts @@ -0,0 +1,89 @@ +import type { EntryDoc, NodeData } from "@lib/common/models/db.definition"; +import type { EntryLeaf, DatabaseEntry } from "@lib/common/models/db.type"; +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import type { SyncParameters } from "@lib/common/models/sync.definition"; +import { LiveSyncAbstractReplicator, type LiveSyncReplicatorEnv, type RemoteDBStatus } from "@lib/replication/LiveSyncAbstractReplicator.ts"; +import type { ServiceHub } from "@lib/services/ServiceHub.ts"; +export interface LiveSyncCouchDBReplicatorEnv extends LiveSyncReplicatorEnv { + services: ServiceHub; +} +export declare class LiveSyncCouchDBReplicator extends LiveSyncAbstractReplicator { + get isChunkSendingSupported(): boolean; + isMobile(): boolean; + constructor(env: LiveSyncCouchDBReplicatorEnv); + getInitialSyncParameters(setting: RemoteDBSettings): Promise; + getSyncParameters(setting: RemoteDBSettings): Promise; + putSyncParameters(setting: RemoteDBSettings, params: SyncParameters): Promise; + getReplicationPBKDF2Salt(setting: RemoteDBSettings, refresh?: boolean): Promise>; + migrate(from: number, to: number): Promise; + terminateSync(): void; + openReplication(setting: RemoteDBSettings, keepAlive: boolean, showResult: boolean, ignoreCleanLock: boolean): Promise; + replicationActivated(showResult: boolean): void; + replicationChangeDetected(e: PouchDB.Replication.SyncResult, showResult: boolean, docSentOnStart: number, docArrivedOnStart: number): Promise; + replicationCompleted(showResult: boolean): void; + replicationDenied(e: unknown): void; + replicationErrored(e: unknown): void; + replicationPaused(): void; + processSync(syncHandler: PouchDB.Replication.Sync | PouchDB.Replication.Replication, showResult: boolean, docSentOnStart: number, docArrivedOnStart: number, syncMode: "sync" | "pullOnly" | "pushOnly", retrying: boolean, reportCancelledAsDone?: boolean): Promise<"DONE" | "NEED_RETRY" | "NEED_RESURRECT" | "FAILED" | "CANCELLED">; + getEmptyMaxEntry(remoteID: number): { + _id: string; + maxSeq: number | string; + remoteID: number; + seqStatusMap: Record; + _rev: string | undefined; + }; + getLastTransferredSeqOfChunks(localDB: PouchDB.Database, remoteID: number): Promise>; + updateMaxTransferredSeqOnChunks(localDB: PouchDB.Database, remoteID: number, seqStatusMap: Record): Promise>; + sendChunks(setting: RemoteDBSettings, remoteDB: PouchDB.Database | undefined, showResult: boolean, fromSeq?: number | string): Promise; + openOneShotReplication(setting: RemoteDBSettings, showResult: boolean, retrying: boolean, syncMode: "sync" | "pullOnly" | "pushOnly", ignoreCleanLock?: boolean): Promise; + replicateAllToServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise; + replicateAllFromServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise; + checkReplicationConnectivity(setting: RemoteDBSettings, keepAlive: boolean, skipCheck: boolean, showResult: boolean, ignoreCleanLock?: boolean): Promise; + info: PouchDB.Core.DatabaseInfo; + syncOptionBase: PouchDB.Replication.SyncOptions; + syncOption: PouchDB.Replication.SyncOptions; + }>; + openContinuousReplication(setting: RemoteDBSettings, showResult: boolean, retrying: boolean): Promise; + closeReplication(): void; + tryResetRemoteDatabase(setting: RemoteDBSettings): Promise; + tryCreateRemoteDatabase(setting: RemoteDBSettings): Promise; + markRemoteLocked(setting: RemoteDBSettings, locked: boolean, lockByClean: boolean): Promise; + markRemoteResolved(setting: RemoteDBSettings): Promise; + connectRemoteCouchDBWithSetting(settings: RemoteDBSettings, isMobile: boolean, performSetup?: boolean, skipInfo?: boolean): Promise; + info: PouchDB.Core.DatabaseInfo; + }> | "Empty passphrases cannot be used without explicit permission"; + _ensureConnection(settings: RemoteDBSettings, performSetup?: boolean): Promise>; + /** + * Fetch a document from the remote database directly. + * @param settings RemoteDBSettings for the connection. + * @param id Document ID to fetch. + * @param db Optional PouchDB instance to use. If provided, it will use this instance instead of creating a new connection (then settings will be ignored). + * @returns The fetched document or false if the document does not exist. + * @throws {Error} Other errors that may occur during the fetch operation. + */ + fetchRemoteDocument(settings: RemoteDBSettings, id: string, db?: PouchDB.Database): Promise; + /** + * Puts a document to the remote database directly + * @param settings RemoteDBSettings for the connection. + * @param doc Document to put. + * @param db Optional PouchDB instance to use. If provided, it will use this instance instead of creating a new connection (then settings will be ignored). + * @returns Response from the remote database or false if an error occurred. + * @throws {Error} If the document could not be put. + */ + putRemoteDocument(settings: RemoteDBSettings, doc: T, db?: PouchDB.Database): Promise; + fetchRemoteChunks(missingChunks: string[], showResult: boolean): Promise; + tryConnectRemote(setting: RemoteDBSettings, showResult?: boolean): Promise; + resetRemoteTweakSettings(setting: RemoteDBSettings): Promise; + setPreferredRemoteTweakSettings(setting: RemoteDBSettings): Promise; + getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise; + compactRemote(setting: RemoteDBSettings): Promise; + getRemoteStatus(setting: RemoteDBSettings): Promise; + countCompromisedChunks(setting?: RemoteDBSettings): Promise; + getConnectedDeviceList(setting?: RemoteDBSettings): Promise; + accepted_nodes: string[]; + }>; +} diff --git a/_types/lib/src/replication/httplib.d.ts b/_types/lib/src/replication/httplib.d.ts new file mode 100644 index 0000000..d0ce92c --- /dev/null +++ b/_types/lib/src/replication/httplib.d.ts @@ -0,0 +1,76 @@ +import type { CouchDBCredentials, JWTCredentials, JWTHeader, JWTParams, JWTPayload, PreparedJWT } from "@lib/common/models/auth.type"; +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import { Computed } from "octagonal-wheels/dataobject/Computed"; +/** + * Generates a credential object based on the provided settings. + * @param settings - RemoteDBSettings + * @returns {CouchDBCredentials} credentials object + */ +export declare function generateCredentialObject(settings: RemoteDBSettings): { + jwtAlgorithm: import("@lib/common/models/auth.type").JWTAlgorithm; + jwtKey: string; + jwtKid: string; + jwtSub: string; + jwtExpDuration: number; + type: "jwt"; + username?: undefined; + password?: undefined; +} | { + username: string; + password: string; + type: "basic"; + jwtAlgorithm?: undefined; + jwtKey?: undefined; + jwtKid?: undefined; + jwtSub?: undefined; + jwtExpDuration?: undefined; +}; +/** + * Generates a basic authentication header for CouchDB credentials using the provided username and password. + * And it caches the result for performance if the credentials are not changed. + */ +export declare class BasicHeaderGenerator { + _header: Computed<[source: CouchDBCredentials], string>; + /** + * Generates a basic authentication header for CouchDB credentials using the provided username and password. + * @param auth - CouchDBCredentials + * @returns {Promise} The basic authentication header (without "Basic" prefix). + */ + getBasicHeader(auth: CouchDBCredentials): Promise; +} +/** + * Generates a JWT token based on the provided credentials and parameters. + * And it caches the result for performance if the credentials are not changed. + */ +export declare class JWTTokenGenerator { + _importKey(auth: JWTCredentials): Promise; + _currentCryptoKey: Computed<[auth: JWTCredentials], CryptoKey>; + _jwt: Computed<[params: JWTParams], { + token: string; + header: JWTHeader; + payload: JWTPayload; + credentials: JWTCredentials; + }>; + _jwtParams: Computed<[source: JWTCredentials], { + header: JWTHeader; + payload: { + exp: number; + iat: number; + sub: string; + "_couchdb.roles": string[]; + }; + credentials: JWTCredentials; + }>; + getJWT(auth: JWTCredentials): Promise; + /** + * Generates a JWT token based on the provided credentials and parameters. + * @param auth - JWTCredentials + * @returns {Promise} The JWT token (with "Bearer" prefix). + */ + getBearerToken(auth: JWTCredentials): Promise; +} +export declare class AuthorizationHeaderGenerator { + _basicHeader: BasicHeaderGenerator; + _jwtHeader: JWTTokenGenerator; + getAuthorizationHeader(auth: CouchDBCredentials): Promise; +} diff --git a/_types/lib/src/replication/journal/JournalSyncAbstract.d.ts b/_types/lib/src/replication/journal/JournalSyncAbstract.d.ts new file mode 100644 index 0000000..1d07d89 --- /dev/null +++ b/_types/lib/src/replication/journal/JournalSyncAbstract.d.ts @@ -0,0 +1,89 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { SyncParameters } from "@lib/common/models/sync.definition"; +import type { BucketSyncSetting, RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { ReplicationCallback, ReplicationStat } from "@lib/replication/LiveSyncAbstractReplicator.ts"; +import { type SimpleStore } from "@lib/common/utils.ts"; +import { type CheckPointInfo } from "./JournalSyncTypes.ts"; +import type { LiveSyncJournalReplicatorEnv } from "./LiveSyncJournalReplicatorEnv.ts"; +import { Trench } from "octagonal-wheels/memory/memutil"; +import { Notifier } from "octagonal-wheels/concurrency/processor"; +type ProcessingEntry = PouchDB.Core.PutDocument & PouchDB.Core.GetMeta; +export declare abstract class JournalSyncAbstract { + _settings: BucketSyncSetting; + get id(): string; + get key(): string; + get bucket(): string; + get endpoint(): string; + get prefix(): string; + get region(): string; + get forcePathStyle(): boolean; + get db(): PouchDB.Database; + /** + * Return current (environmental) settings, not the instance settings. + */ + get currentSettings(): import("@lib/common/models/setting.type").ObsidianLiveSyncSettings; + hash: string; + processReplication: ReplicationCallback; + batchSize: number; + env: LiveSyncJournalReplicatorEnv; + store: SimpleStore; + get useCustomRequestHandler(): boolean; + get customHeaders(): [string, string][]; + requestedStop: boolean; + trench: Trench; + notifier: Notifier; + getInitialSyncParameters(): Promise; + getSyncParameters(): Promise; + putSyncParameters(params: SyncParameters): Promise; + getHash(settings: BucketSyncSetting): string; + constructor(settings: BucketSyncSetting, store: SimpleStore, env: LiveSyncJournalReplicatorEnv); + applyNewConfig(settings: BucketSyncSetting, store: SimpleStore, env: LiveSyncJournalReplicatorEnv): void; + updateInfo(info: Partial): void; + updateCheckPointInfo(func: (infoFrom: CheckPointInfo) => CheckPointInfo): Promise; + _currentCheckPointInfo: { + lastLocalSeq: number | string; + journalEpoch: string; + knownIDs: Set; + sentIDs: Set; + receivedFiles: Set; + sentFiles: Set; + }; + getCheckpointInfo(): Promise; + resetAllCaches(): Promise; + resetCheckpointInfo(): Promise; + private getJournalEpochFromSyncParams; + ensureCheckpointCachesAreFresh(): Promise; + abstract resetBucket(): Promise; + abstract uploadJson(key: string, body: unknown): Promise; + abstract downloadJson(key: string): Promise; + abstract uploadFile(key: string, blob: Blob, mime: string): Promise; + abstract downloadFile(key: string): Promise; + abstract listFiles(from: string, limit?: number): Promise; + abstract isAvailable(): Promise; + getRemoteKey(): string; + getReplicationPBKDF2Salt(refresh?: boolean): Promise>; + isEncryptionPrevented(fileName: string): boolean; + private decryptDataV2; + private decryptDataV1; + decryptDownloaded(key: string, encrypted: Uint8Array, set: RemoteDBSettings): Promise>; + encryptForUpload(key: string, data: Uint8Array, set: RemoteDBSettings): Promise>; + _createJournalPack(override?: number | string): Promise<{ + changes: (EntryDoc & PouchDB.Core.GetMeta)[]; + hasNext: boolean; + packLastSeq: string | number; + }>; + getDocKey(doc: EntryDoc): string; + uploadQueued(showMessage?: boolean, wrapUp?: boolean): Promise; + isPacking: boolean; + packAndCompress(showMessage?: boolean): Promise; + sendLocalJournal(showMessage?: boolean): Promise; + _getRemoteJournals(): Promise; + processDocuments(allDocs: ProcessingEntry[]): Promise; + processDownloadedJournals(showMessage?: boolean, wrapUp?: boolean): Promise; + isDownloading: boolean; + downloadRemoteJournals(showMessage?: boolean): Promise; + receiveRemoteJournal(showMessage?: boolean): Promise; + sync(showResult?: boolean): Promise; + requestStop(): void; +} +export {}; diff --git a/_types/lib/src/replication/journal/JournalSyncTypes.d.ts b/_types/lib/src/replication/journal/JournalSyncTypes.d.ts new file mode 100644 index 0000000..980f87c --- /dev/null +++ b/_types/lib/src/replication/journal/JournalSyncTypes.d.ts @@ -0,0 +1,9 @@ +export type CheckPointInfo = { + lastLocalSeq: number | string; + journalEpoch: string; + knownIDs: Set; + sentIDs: Set; + receivedFiles: Set; + sentFiles: Set; +}; +export declare const CheckPointInfoDefault: CheckPointInfo; diff --git a/_types/lib/src/replication/journal/LiveSyncJournalReplicator.d.ts b/_types/lib/src/replication/journal/LiveSyncJournalReplicator.d.ts new file mode 100644 index 0000000..5bea059 --- /dev/null +++ b/_types/lib/src/replication/journal/LiveSyncJournalReplicator.d.ts @@ -0,0 +1,43 @@ +import type { NodeData } from "@lib/common/models/db.definition"; +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { EntryLeaf, ChunkVersionRange } from "@lib/common/models/db.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import { JournalSyncMinio } from "./objectstore/JournalSyncMinio.ts"; +import { LiveSyncAbstractReplicator, type RemoteDBStatus } from "@lib/replication/LiveSyncAbstractReplicator.ts"; +import { type ENSURE_DB_RESULT } from "@lib/pouchdb/LiveSyncDBFunctions.ts"; +import type { CheckPointInfo } from "./JournalSyncTypes.ts"; +import { type SimpleStore } from "@lib/common/utils.ts"; +import type { LiveSyncJournalReplicatorEnv } from "./LiveSyncJournalReplicatorEnv.ts"; +export declare class LiveSyncJournalReplicator extends LiveSyncAbstractReplicator { + env: LiveSyncJournalReplicatorEnv; + get isChunkSendingSupported(): boolean; + get client(): JournalSyncMinio; + get simpleStore(): SimpleStore; + _client: JournalSyncMinio; + getReplicationPBKDF2Salt(setting: RemoteDBSettings, refresh?: boolean): Promise>; + setupJournalSyncClient(): JournalSyncMinio; + ensureBucketIsCompatible(deviceNodeID: string, currentVersionRange: ChunkVersionRange): Promise; + constructor(env: LiveSyncJournalReplicatorEnv); + migrate(from: number, to: number): Promise; + terminateSync(): void; + openReplication(setting: RemoteDBSettings, _: boolean, showResult: boolean, ignoreCleanLock?: boolean): Promise; + replicateAllToServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise; + replicateAllFromServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise; + checkReplicationConnectivity(skipCheck: boolean, ignoreCleanLock?: boolean, showMessage?: boolean): Promise; + fetchRemoteChunks(missingChunks: string[], showResult: boolean): Promise; + closeReplication(): void; + tryResetRemoteDatabase(setting: RemoteDBSettings): Promise; + tryCreateRemoteDatabase(setting: RemoteDBSettings): Promise; + markRemoteLocked(setting: RemoteDBSettings, locked: boolean, lockByClean: boolean): Promise; + markRemoteResolved(setting: RemoteDBSettings): Promise; + tryConnectRemote(setting: RemoteDBSettings, showResult?: boolean): Promise; + resetRemoteTweakSettings(setting: RemoteDBSettings): Promise; + setPreferredRemoteTweakSettings(setting: RemoteDBSettings): Promise; + getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise; + getRemoteStatus(setting: RemoteDBSettings): Promise; + countCompromisedChunks(): Promise; + getConnectedDeviceList(setting?: RemoteDBSettings): Promise; + accepted_nodes: string[]; + }>; +} diff --git a/_types/lib/src/replication/journal/LiveSyncJournalReplicatorEnv.d.ts b/_types/lib/src/replication/journal/LiveSyncJournalReplicatorEnv.d.ts new file mode 100644 index 0000000..b9bb994 --- /dev/null +++ b/_types/lib/src/replication/journal/LiveSyncJournalReplicatorEnv.d.ts @@ -0,0 +1,5 @@ +import type { IServiceHub } from "@lib/services/base/IService"; +import type { LiveSyncReplicatorEnv } from "@lib/replication/LiveSyncAbstractReplicator"; +export interface LiveSyncJournalReplicatorEnv extends LiveSyncReplicatorEnv { + services: IServiceHub; +} diff --git a/_types/lib/src/replication/journal/objectstore/JournalSyncMinio.d.ts b/_types/lib/src/replication/journal/objectstore/JournalSyncMinio.d.ts new file mode 100644 index 0000000..52b9fae --- /dev/null +++ b/_types/lib/src/replication/journal/objectstore/JournalSyncMinio.d.ts @@ -0,0 +1,15 @@ +import { S3 } from "@aws-sdk/client-s3"; +import { JournalSyncAbstract } from "@lib/replication/journal/JournalSyncAbstract.ts"; +import type { RemoteDBStatus } from "@lib/replication/LiveSyncAbstractReplicator.ts"; +export declare class JournalSyncMinio extends JournalSyncAbstract { + _instance?: S3; + _getClient(): S3; + resetBucket(): Promise; + uploadJson(key: string, body: unknown): Promise; + downloadJson(key: string): Promise; + uploadFile(key: string, blob: Blob, mime: string): Promise; + downloadFile(key: string, ignoreCache?: boolean): Promise; + listFiles(from: string, limit?: number): Promise; + isAvailable(): Promise; + getUsage(): Promise; +} diff --git a/_types/lib/src/replication/trystero/LiveSyncTrysteroReplicator.d.ts b/_types/lib/src/replication/trystero/LiveSyncTrysteroReplicator.d.ts new file mode 100644 index 0000000..7319fed --- /dev/null +++ b/_types/lib/src/replication/trystero/LiveSyncTrysteroReplicator.d.ts @@ -0,0 +1,96 @@ +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { EntryLeaf } from "@lib/common/models/db.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import type { LOG_LEVEL } from "@lib/common/logger"; +import type { NodeData } from "@lib/common/models/db.definition"; +import { LiveSyncAbstractReplicator, type LiveSyncReplicatorEnv, type RemoteDBStatus } from "@lib/replication/LiveSyncAbstractReplicator"; +import { TrysteroReplicator } from "./TrysteroReplicator"; +import { P2PHost, type AcceptanceDecision, type RevokeAcceptanceDecision } from "./TrysteroReplicatorP2PServer"; +import type { IServiceHub } from "@lib/services/base/IService"; +import type { Advertisement } from "./types"; +export interface LiveSyncTrysteroReplicatorEnv extends LiveSyncReplicatorEnv { + services: IServiceHub; + /** + * Injected by the host platform (e.g. Obsidian) to show a UI for peer selection. + * When not set, openReplication falls back to replicateFromCommand (CLI-safe). + */ + openReplicationUI?: (showResult: boolean) => Promise; + /** + * Injected by the host platform to show a UI for selecting a peer to rebuild from. + * When not set, replicateAllFromServer falls back to the headless selectPeer dialog. + */ + openRebuildUI?: (showResult: boolean) => Promise; +} +export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator { + private _p2pHost?; + private _replicator?; + get openReplicationUI(): ((showResult: boolean) => Promise) | undefined; + get rawReplicator(): TrysteroReplicator | undefined; + get rawHost(): P2PHost | undefined; + get isChunkSendingSupported(): boolean; + getReplicationPBKDF2Salt(_setting: RemoteDBSettings, _refresh?: boolean): Promise>; + terminateSync(): void; + private _buildEnv; + open(): Promise; + close(): Promise; + closeReplication(): void; + get server(): P2PHost | undefined; + get knownAdvertisements(): Advertisement[]; + enableBroadcastChanges(): void; + disableBroadcastChanges(): void; + requestStatus(): void; + onNewPeer(peer: Advertisement): Promise | undefined; + onPeerLeaved(peerId: string): void; + replicateFromCommand(showResult?: boolean): Promise; + replicateFrom(peerId: string, showNotice?: boolean): Promise<{ + error: unknown; + ok?: undefined; + } | { + ok: boolean; + error?: undefined; + }>; + requestSynchroniseToPeer(peerId: string): Promise<{ + error: unknown; + ok?: undefined; + } | { + ok: boolean; + error?: undefined; + }>; + getRemoteConfig(peerId: string): Promise; + watchPeer(peerId: string): void; + unwatchPeer(peerId: string): void; + sync(peerId: string, showNotice?: boolean): Promise<{ + error: unknown; + ok?: undefined; + } | { + ok: boolean; + error?: undefined; + } | undefined>; + setOnSetup(): void; + clearOnSetup(): void; + makeDecision(decision: AcceptanceDecision): Promise; + revokeDecision(decision: RevokeAcceptanceDecision): Promise; + makeSureOpened(): Promise; + openReplication(_setting: RemoteDBSettings, _keepAlive: boolean, showResult: boolean, _ignoreCleanLock: boolean): Promise; + tryConnectRemote(_setting: RemoteDBSettings, _showResult?: boolean): Promise; + replicateAllToServer(_setting: RemoteDBSettings, _showingNotice?: boolean, _sendChunksInBulkDisabled?: boolean): Promise; + selectPeer(settingPeerName: string, r: TrysteroReplicator, logLevel: LOG_LEVEL): Promise; + tryUntilSuccess(func: () => Promise, repeat: number, logLevel: LOG_LEVEL): Promise; + replicateAllFromServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise; + tryResetRemoteDatabase(_setting: RemoteDBSettings): Promise; + tryCreateRemoteDatabase(_setting: RemoteDBSettings): Promise; + markRemoteLocked(_setting: RemoteDBSettings, _locked: boolean, _lockByClean: boolean): Promise; + markRemoteResolved(_setting: RemoteDBSettings): Promise; + resetRemoteTweakSettings(_setting: RemoteDBSettings): Promise; + setPreferredRemoteTweakSettings(_setting: RemoteDBSettings): Promise; + fetchRemoteChunks(_missingChunks: string[], _showResult: boolean): Promise; + getRemoteStatus(_setting: RemoteDBSettings): Promise; + getRemotePreferredTweakValues(_setting: RemoteDBSettings): Promise; + countCompromisedChunks(): Promise; + getConnectedDeviceList(_setting?: RemoteDBSettings): Promise; + accepted_nodes: string[]; + }>; + env: LiveSyncTrysteroReplicatorEnv; + constructor(env: LiveSyncTrysteroReplicatorEnv); +} diff --git a/_types/lib/src/replication/trystero/P2PLogCollector.d.ts b/_types/lib/src/replication/trystero/P2PLogCollector.d.ts new file mode 100644 index 0000000..3016582 --- /dev/null +++ b/_types/lib/src/replication/trystero/P2PLogCollector.d.ts @@ -0,0 +1,7 @@ +import type { P2PReplicationProgress } from "./TrysteroReplicator"; +export declare class P2PLogCollector { + constructor(); + p2pReplicationResult: Map; + updateP2PReplicationLine(): void; + p2pReplicationLine: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +} diff --git a/_types/lib/src/replication/trystero/P2PReplicatorBase.d.ts b/_types/lib/src/replication/trystero/P2PReplicatorBase.d.ts new file mode 100644 index 0000000..4228c1e --- /dev/null +++ b/_types/lib/src/replication/trystero/P2PReplicatorBase.d.ts @@ -0,0 +1,20 @@ +import type { LOG_LEVEL } from "octagonal-wheels/common/logger"; +import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase"; +import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2"; +import type { P2PSyncSetting } from "@lib/common/models/setting.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices"; +export interface P2PReplicatorBase { + storeP2PStatusLine: ReactiveSource; + settings: P2PSyncSetting; + _log(msg: unknown, level?: LOG_LEVEL): void; + _notice(msg: unknown, key?: string): void; + getSettings(): P2PSyncSetting; + getDB: () => PouchDB.Database; + confirm: Confirm; + simpleStore(): SimpleStore; + handleReplicatedDocuments(docs: EntryDoc[]): Promise; + init(): Promise; + services: InjectableServiceHub; +} diff --git a/_types/lib/src/replication/trystero/P2PReplicatorCore.d.ts b/_types/lib/src/replication/trystero/P2PReplicatorCore.d.ts new file mode 100644 index 0000000..e548609 --- /dev/null +++ b/_types/lib/src/replication/trystero/P2PReplicatorCore.d.ts @@ -0,0 +1,12 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import type { P2PPaneParams } from "./UseP2PReplicatorResult"; +export type P2PViewFactory = (leaf: any) => any; +/** + * ServiceFeature: P2P Replicator lifecycle management. + * Binds a LiveSyncTrysteroReplicator to the host's lifecycle events, + * following the same middleware style as useOfflineScanner. + * + * @param viewTypeAndFactory Optional [viewType, factory] pair for registering the P2P pane view. + * When provided, also registers commands and ribbon icon via services.API. + */ +export declare function useP2PReplicator(host: NecessaryServices<"API" | "appLifecycle" | "setting" | "vault" | "database" | "databaseEvents" | "keyValueDB" | "replication" | "config" | "UI" | "replicator", never>, viewTypeAndFactory?: [viewType: string, factory: P2PViewFactory]): P2PPaneParams; diff --git a/_types/lib/src/replication/trystero/P2PReplicatorPaneCommon.d.ts b/_types/lib/src/replication/trystero/P2PReplicatorPaneCommon.d.ts new file mode 100644 index 0000000..7867cf1 --- /dev/null +++ b/_types/lib/src/replication/trystero/P2PReplicatorPaneCommon.d.ts @@ -0,0 +1,41 @@ +import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts"; +export declare const EVENT_P2P_PEER_SHOW_EXTRA_MENU = "p2p-peer-show-extra-menu"; +export declare enum AcceptedStatus { + UNKNOWN = "Unknown", + ACCEPTED = "Accepted", + DENIED = "Denied", + ACCEPTED_IN_SESSION = "Accepted in session", + DENIED_IN_SESSION = "Denied in session" +} +export type PeerExtraMenuEvent = { + peer: PeerStatus; + event: MouseEvent; +}; +export declare enum ConnectionStatus { + CONNECTED = "Connected", + CONNECTED_LIVE = "Connected(live)", + DISCONNECTED = "Disconnected" +} +export type PeerStatus = { + name: string; + peerId: string; + syncOnConnect: boolean; + watchOnConnect: boolean; + syncOnReplicationCommand: boolean; + accepted: AcceptedStatus; + status: ConnectionStatus; + isFetching: boolean; + isSending: boolean; + isWatching: boolean; +}; +declare global { + interface LSEvents { + [EVENT_P2P_PEER_SHOW_EXTRA_MENU]: PeerExtraMenuEvent; + } +} +export interface PluginShim { + services: InjectableServiceHub; + core: { + services: InjectableServiceHub; + }; +} diff --git a/_types/lib/src/replication/trystero/ProxiedDB.d.ts b/_types/lib/src/replication/trystero/ProxiedDB.d.ts new file mode 100644 index 0000000..f519e98 --- /dev/null +++ b/_types/lib/src/replication/trystero/ProxiedDB.d.ts @@ -0,0 +1,12 @@ +import { type ReplicatorHostEnv } from "./types"; +export declare function createHostingDB(env: ReplicatorHostEnv): { + info: () => Promise; + changes: (options: PouchDB.Core.ChangesOptions) => PouchDB.Core.Changes; + revsDiff: (diff: PouchDB.Core.RevisionDiffOptions) => Promise; + bulkDocs: (docs: PouchDB.Core.PostDocument[], options?: PouchDB.Core.BulkDocsOptions) => Promise<(PouchDB.Core.Response | PouchDB.Core.Error)[]>; + bulkGet: (options: PouchDB.Core.BulkGetOptions) => Promise>; + put: (doc: PouchDB.Core.PutDocument, options?: PouchDB.Core.PutOptions) => Promise; + get: (id: string, options?: PouchDB.Core.GetOptions) => Promise; + _stopHosting: () => void; +}; +export type HostingDB = ReturnType; diff --git a/_types/lib/src/replication/trystero/TrysteroReplicator.d.ts b/_types/lib/src/replication/trystero/TrysteroReplicator.d.ts new file mode 100644 index 0000000..f0a395f --- /dev/null +++ b/_types/lib/src/replication/trystero/TrysteroReplicator.d.ts @@ -0,0 +1,151 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import { type ProgressInfo } from "@lib/pouchdb/ReplicatorShim"; +import type { Confirm } from "@lib/interfaces/Confirm"; +import { type Advertisement, type ReplicatorHostEnv } from "./types"; +import { EVENT_P2P_REPLICATOR_PROGRESS, EVENT_P2P_REPLICATOR_STATUS, P2PHost } from "./TrysteroReplicatorP2PServer"; +export type P2PReplicatorStatus = { + isBroadcasting: boolean; + replicatingTo: string[]; + replicatingFrom: string[]; + watchingPeers: string[]; +}; +export type P2PReplicationProgress = { + peerId: string; + peerName: string; + fetching: { + max: number; + current: number; + isActive: boolean; + }; + sending: { + max: number; + current: number; + isActive: boolean; + }; +}; +export type P2PReplicationReport = { + peerId: string; + peerName: string; +} & ({ + fetching: { + max: number; + current: number; + isActive: boolean; + }; +} | { + sending: { + max: number; + current: number; + isActive: boolean; + }; +}); +declare global { + interface LSEvents { + [EVENT_P2P_REPLICATOR_STATUS]: P2PReplicatorStatus; + [EVENT_P2P_REPLICATOR_PROGRESS]: P2PReplicationReport; + } +} +export type AllReplicationClientStatus = { + [peerId: string]: { + isReplicatingTo: boolean; + isReplicatingFrom: boolean; + isWatching: boolean; + stats: P2PReplicationProgress; + }; +}; +export declare class TrysteroReplicator { + _env: ReplicatorHostEnv; + server?: P2PHost; + replicationStatus(): {}; + get settings(): import("@lib/common/models/setting.type").P2PSyncSetting; + get db(): PouchDB.Database; + get deviceName(): string; + get platform(): string; + get confirm(): Confirm; + constructor(env: ReplicatorHostEnv, server?: P2PHost); + close(): Promise; + open(): Promise; + makeSureOpened(): Promise; + get autoSyncPeers(): RegExp[]; + get autoWatchPeers(): RegExp[]; + onNewPeer(peer: Advertisement): Promise; + onPeerLeaved(peerId: string): void; + _onSetup: boolean; + setOnSetup(): void; + clearOnSetup(): void; + getTweakSettings(fromPeerId: string): Promise>; + getCommands(): { + reqSync: (fromPeerId: string) => Promise<{ + error: unknown; + ok?: undefined; + } | { + ok: boolean; + error?: undefined; + }>; + "!reqAuth": (fromPeerId: string) => Promise; + getTweakSettings: (fromPeerId: string) => Promise>; + onProgress: (fromPeerId: string) => Promise<{ + error: Error; + } | undefined>; + getAllConfig: (fromPeerId: string) => Promise; + onProgressAcknowledged: (fromPeerId: string, info: ProgressInfo) => Promise; + getIsBroadcasting: () => Promise; + requestBroadcasting: (peerId: string) => Promise; + }; + requestAuthenticate(peerId: string): Promise; + lastSeq: string | number; + requestSynchroniseToPeer(peerId: string): Promise["reqSync"]>>>; + requestSynchroniseToAllAvailablePeers(): Promise; + dispatchStatus(): void; + requestStatus(): void; + changes?: PouchDB.Core.Changes; + _isBroadcasting: boolean; + disableBroadcastChanges(): void; + enableBroadcastChanges(): void; + get knownAdvertisements(): Advertisement[]; + availableReplicationPairs: Set; + sync(remotePeer: string, showNotice?: boolean): Promise<{ + error: unknown; + ok?: undefined; + } | { + ok: boolean; + error?: undefined; + } | undefined>; + _replicateToPeers: Set; + _replicateFromPeers: Set; + dispatchReplicationProgress(peerId: string, info?: ProgressInfo): void; + onReplicationProgress(peerId: string, info?: ProgressInfo): boolean; + onProgressAcknowledged(peerId: string, info?: ProgressInfo): boolean; + acknowledgeProgress(remotePeerId: string, info?: ProgressInfo): void; + replicateFrom(remotePeer: string, showNotice?: boolean, fromStart?: boolean): Promise<{ + error: unknown; + ok?: undefined; + } | { + ok: boolean; + error?: undefined; + }>; + notifyProgress(excludePeerId?: string): Promise | undefined; + requestBroadcastChanges(peerId: string): Promise; + getRemoteIsBroadcasting(peerId: string): Promise; + _watchingPeers: Set; + watchPeer(peerId: string): void; + unwatchPeer(peerId: string): void; + onUpdateDatabase(fromPeerId: string): Promise; + getRemoteConfig(peerId: string): Promise; + checkTweakValues(peerId: string): Promise; + replicateFromCommand(showResult?: boolean): Promise; + disconnectFromServer(): void; + pauseServe(): Promise; + allowReconnection(): void; +} diff --git a/_types/lib/src/replication/trystero/TrysteroReplicatorP2PClient.d.ts b/_types/lib/src/replication/trystero/TrysteroReplicatorP2PClient.d.ts new file mode 100644 index 0000000..49c1c6c --- /dev/null +++ b/_types/lib/src/replication/trystero/TrysteroReplicatorP2PClient.d.ts @@ -0,0 +1,19 @@ +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { PouchDBShim } from "@lib/pouchdb/ReplicatorShim"; +import type { TrysteroReplicatorP2PServer } from "./TrysteroReplicatorP2PServer"; +import { type BindableObject, type NonPrivateMethodKeys } from "./types"; +export declare class TrysteroReplicatorP2PClient { + _server: TrysteroReplicatorP2PServer; + _connectedPeerId: string; + _remoteDB: PouchDBShim; + get remoteDB(): PouchDBShim; + constructor(server: TrysteroReplicatorP2PServer, connectedPeerId: string); + _bindRemoteDB(): PouchDBShim; + _sendRPC(type: string, args: any[], timeout?: number): Promise; + __onResponse(_data: unknown): void; + bindRemoteFunction(type: string, timeout?: number): (...args: T) => Promise; + invokeRemoteFunction(type: string, args: T, timeout?: number): Promise; + bindRemoteObjectFunctions, U extends keyof T>(key: U, timeout?: number): (...args: Parameters) => Promise>>; + invokeRemoteObjectFunction, U extends NonPrivateMethodKeys>(key: U, args: Parameters, timeout?: number): Promise>>; + close(): void; +} diff --git a/_types/lib/src/replication/trystero/TrysteroReplicatorP2PConnection.d.ts b/_types/lib/src/replication/trystero/TrysteroReplicatorP2PConnection.d.ts new file mode 100644 index 0000000..a0e13cc --- /dev/null +++ b/_types/lib/src/replication/trystero/TrysteroReplicatorP2PConnection.d.ts @@ -0,0 +1,2 @@ +import { TrysteroReplicatorP2PServer } from "./TrysteroReplicatorP2PServer"; +export { TrysteroReplicatorP2PServer as TrysteroConnection }; diff --git a/_types/lib/src/replication/trystero/TrysteroReplicatorP2PServer.d.ts b/_types/lib/src/replication/trystero/TrysteroReplicatorP2PServer.d.ts new file mode 100644 index 0000000..553a2a5 --- /dev/null +++ b/_types/lib/src/replication/trystero/TrysteroReplicatorP2PServer.d.ts @@ -0,0 +1,117 @@ +import { type ActionSender, type Room } from "@trystero-p2p/nostr"; +import type { P2PSyncSetting } from "@lib/common/models/setting.type"; +import { type ReplicatorHostEnv, type FullFilledDeviceInfo, type Request, type Response, type Payload, type Advertisement, type BindableObject } from "./types"; +import { StoredMapLike } from "@lib/dataobject/StoredMap"; +import { TrysteroReplicatorP2PClient } from "./TrysteroReplicatorP2PClient"; +import { Computed } from "octagonal-wheels/dataobject/Computed"; +import { RpcRoom, type JsonLike } from "@lib/rpc"; +import { type DiagRTCStats } from "@lib/rpc/transports/DiagRTCPeerConnections.types"; +export type PeerInfo = Advertisement & { + isAccepted: boolean | undefined; + isTemporaryAccepted: boolean | undefined; +}; +export type AcceptanceDecision = { + peerId: string; + name: string; + decision: boolean; + isTemporary: boolean; +}; +export type RevokeAcceptanceDecision = { + peerId: string; + name: string; +}; +export type P2PServerInfo = { + isConnected: boolean; + knownAdvertisements: PeerInfo[]; + serverPeerId: string; + roomId: string; + diag: DiagRTCStats; +}; +export declare const EVENT_SERVER_STATUS = "p2p-server-status"; +export declare const EVENT_MAKE_DECISION = "make-decision-p2p-peer"; +export declare const EVENT_REVOKE_DECISION = "revoke-decision-p2p-peer"; +export declare const EVENT_ADVERTISEMENT_RECEIVED = "p2p-advertisement-received"; +export declare const EVENT_DEVICE_LEAVED = "p2p-device-leaved"; +export declare const EVENT_REQUEST_STATUS = "p2p-request-status"; +export declare const EVENT_P2P_REQUEST_FORCE_OPEN = "p2p-request-force-open"; +export declare const EVENT_P2P_CONNECTED = "p2p-connected"; +export declare const EVENT_P2P_DISCONNECTED = "p2p-disconnected"; +export declare const EVENT_P2P_REPLICATOR_STATUS = "p2p-replicator-status"; +export declare const EVENT_P2P_REPLICATOR_PROGRESS = "p2p-replicator-progress"; +declare global { + interface LSEvents { + [EVENT_SERVER_STATUS]: P2PServerInfo; + [EVENT_MAKE_DECISION]: AcceptanceDecision; + [EVENT_REVOKE_DECISION]: RevokeAcceptanceDecision; + [EVENT_ADVERTISEMENT_RECEIVED]: Advertisement; + [EVENT_DEVICE_LEAVED]: string; + [EVENT_REQUEST_STATUS]: undefined; + [EVENT_P2P_REQUEST_FORCE_OPEN]: undefined; + [EVENT_P2P_CONNECTED]: undefined; + [EVENT_P2P_DISCONNECTED]: undefined; + } +} +export declare class TrysteroReplicatorP2PServer { + _env: ReplicatorHostEnv; + _room?: Room; + _serverPeerId: string; + _activeRoomId: string; + ___send?: ActionSender; + assignedFunctions: Map any>; + clients: Map; + _bindingObjects: BindableObject[]; + _rpcRoom?: RpcRoom; + protected _peerStatusEventCleanup: (() => void) | undefined; + protected _peerFailureAnalysisCleanup: (() => void) | undefined; + protected _peerConnectionEventCleanup(): void; + _diagStats: DiagRTCStats; + get isDisposed(): boolean; + get isServing(): boolean; + ensureLeaved(): Promise; + setRoom(room: Room): Promise; + shutdown(): Promise; + dispatchConnectionStatus(): Promise; + constructor(env: ReplicatorHostEnv, _serverPeerId?: string); + makeDecision(decision: AcceptanceDecision): Promise; + revokeDecision(decision: RevokeAcceptanceDecision): Promise; + get room(): Room | undefined; + get serverPeerId(): string; + get db(): PouchDB.Database; + get confirm(): import("../../interfaces/Confirm").Confirm; + get settings(): P2PSyncSetting; + get isEnabled(): boolean; + get deviceInfo(): FullFilledDeviceInfo; + _sendAdvertisement?: ActionSender; + sendAdvertisement(peerId?: string): void; + _knownAdvertisements: Map; + get knownAdvertisements(): Advertisement[]; + onAdvertisement(data: Advertisement, peerId: string): void; + acceptedPeers: StoredMapLike; + temporaryAcceptedPeers: Map; + confirmUserToAccept(peerId: string): Promise; + _confirmUserToAccept(peerId: string): Promise; + _acceptablePeers: Computed<[settings: P2PSyncSetting], RegExp[]>; + _shouldDenyPeers: Computed<[settings: P2PSyncSetting], RegExp[]>; + isAcceptablePeer(peerId: string): Promise; + __send(data: Payload, peerId: string): Promise; + processArrivedRPC(data: Payload, peerId: string): Promise; + private _onPeerJoin; + private _onPeerLeave; + activePeer: Map; + onAfterJoinRoom(): void; + startService(bindings?: BindableObject[]): Promise; + start(bindings?: BindableObject[]): Promise; + /** + * @deprecated Use serveFunction or serveObject instead. This is only for backward compatibility and may be removed in the future. + * @param type + * @param func + */ + serveFunction(type: string, func: (peerId: string, ...args: T) => U | Promise): void; + serveObject(obj: BindableObject): void; + __onResponse(data: Response, peerId: string): void; + __onRequest(data: Request, peerId: string): Promise; + close(): Promise; + getConnection(peerId: string): TrysteroReplicatorP2PClient; + get rpcRoom(): RpcRoom | undefined; +} +export { TrysteroReplicatorP2PServer as P2PHost }; diff --git a/_types/lib/src/replication/trystero/UseP2PReplicatorResult.d.ts b/_types/lib/src/replication/trystero/UseP2PReplicatorResult.d.ts new file mode 100644 index 0000000..e09fa68 --- /dev/null +++ b/_types/lib/src/replication/trystero/UseP2PReplicatorResult.d.ts @@ -0,0 +1,11 @@ +import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2"; +import type { LiveSyncTrysteroReplicator } from "./LiveSyncTrysteroReplicator"; +import type { P2PLogCollector } from "./P2PLogCollector"; +export type UseP2PReplicatorResult = { + replicator: LiveSyncTrysteroReplicator; +}; +export type P2PPaneParams = { + replicator: LiveSyncTrysteroReplicator; + p2pLogCollector: P2PLogCollector; + storeP2PStatusLine: ReactiveSource; +}; diff --git a/_types/lib/src/replication/trystero/addP2PEventHandlers.d.ts b/_types/lib/src/replication/trystero/addP2PEventHandlers.d.ts new file mode 100644 index 0000000..2d3a70b --- /dev/null +++ b/_types/lib/src/replication/trystero/addP2PEventHandlers.d.ts @@ -0,0 +1,34 @@ +import type { LiveSyncTrysteroReplicator } from "./LiveSyncTrysteroReplicator"; +import type { Advertisement } from "./types"; +/** + * Minimal interface that a P2P replicator instance should satisfy for addP2PEventHandlers to work. + */ +export interface P2PReplicatorLike { + onNewPeer(peer: Advertisement): Promise | void; + onPeerLeaved(peerId: string): void; + requestStatus(): void; + open(): Promise; + close(): Promise; + /** Indicates whether the room is currently active. */ + readonly isServing?: boolean; + /** Legacy: host object that may carry isServing (LiveSyncTrysteroReplicator). */ + readonly server?: { + isServing?: boolean; + }; +} +/** + * Add event handlers for P2P replication related events. + * @param instance P2PReplicatorLike instance + */ +export declare function addP2PEventHandlers(instance: P2PReplicatorLike): void; +/** + * open P2P replicator if not opened yet. + * @param instance + */ +export declare function openP2PReplicator(instance: P2PReplicatorLike): Promise; +/** + * close P2P replicator + * @param instance + */ +export declare function closeP2PReplicator(instance: P2PReplicatorLike): Promise; +export type { LiveSyncTrysteroReplicator }; diff --git a/_types/lib/src/replication/trystero/rpcCompat.d.ts b/_types/lib/src/replication/trystero/rpcCompat.d.ts new file mode 100644 index 0000000..eb6161c --- /dev/null +++ b/_types/lib/src/replication/trystero/rpcCompat.d.ts @@ -0,0 +1 @@ +export declare function toRpcMethodName(method: string): string; diff --git a/_types/lib/src/replication/trystero/types.d.ts b/_types/lib/src/replication/trystero/types.d.ts new file mode 100644 index 0000000..2683931 --- /dev/null +++ b/_types/lib/src/replication/trystero/types.d.ts @@ -0,0 +1,86 @@ +import type { P2PSyncSetting } from "@lib/common/models/setting.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { SimpleStore } from "@lib/common/utils"; +import type { Confirm } from "@lib/interfaces/Confirm"; +export declare const DIRECTION_REQUEST = "request"; +export type DIRECTION_REQUEST = typeof DIRECTION_REQUEST; +export declare const DIRECTION_RESPONSE = "response"; +export type DIRECTION_RESPONSE = typeof DIRECTION_RESPONSE; +export declare const DEFAULT_RPC_TIMEOUT = 30000; +export declare const BULK_GET_RPC_TIMEOUT = 40000; +export type NonPrivateMethodKeys = { + [K in keyof T]: K extends `_${string}` ? never : K extends `constructor` ? never : T[K] extends (...args: any[]) => any ? K : never; +}[keyof T]; +export type BindableObject = { + [k in NonPrivateMethodKeys]: (...args: any[]) => any; +}; +export type ConnectionInfo = { + relayURIs: string[]; + roomId: string; + password: string; + appId: string; +}; +export declare class ResponsePreventedError extends Error { + constructor(message: string); +} +export type Request = { + type: string; + direction: DIRECTION_REQUEST; + seq: number; + args: any[]; +}; +export type Response = { + type: string; + direction: DIRECTION_RESPONSE; + seq: number; + data?: any; + error?: any; +}; +export type DeviceInfo = { + currentPeerId: string; + name?: string; + version?: string; + platform?: string; + decision?: DeviceDecisions; +}; +export type DeviceInfoForRequest = { + currentPeerId: string; + name: string; +}; +export type FullFilledDeviceInfo = { + currentPeerId: string; + name: string; + version: string; + platform: string; + decision?: DeviceDecisions; +}; +export declare enum DeviceDecisions { + ACCEPT = "accepted", + REJECT = "rejected", + IGNORE = "ignore" +} +export declare const ID_P2PKnownDevices = "_local/P2PKnownDevices"; +export type KnownDevices = { + _id: typeof ID_P2PKnownDevices; + devices: { + [deviceName: string]: DeviceDecisions; + }; +}; +export type Payload = Request | Response; +export interface ReplicatorHost { + deviceName: string; + platform: string; + confirm: Confirm; +} +export interface ReplicatorHostEnv extends ReplicatorHost { + settings: P2PSyncSetting; + db: PouchDB.Database; + simpleStore: SimpleStore; + processReplicatedDocs(docs: Array>): void | Promise; +} +export type Advertisement = { + peerId: string; + name: string; + platform: string; +}; +export declare const KEY_DEVICE_DECISIONS = "p2p-device-decisions"; diff --git a/_types/lib/src/replication/trystero/useP2PReplicatorCommands.d.ts b/_types/lib/src/replication/trystero/useP2PReplicatorCommands.d.ts new file mode 100644 index 0000000..e5bc664 --- /dev/null +++ b/_types/lib/src/replication/trystero/useP2PReplicatorCommands.d.ts @@ -0,0 +1,7 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import type { UseP2PReplicatorResult } from "./UseP2PReplicatorResult"; +/** + * ServiceFeature: Registers event handlers for P2P replication and manages the lifecycle of a LiveSyncTrysteroReplicator instance. + * @param host + */ +export declare function useP2PReplicatorCommands(host: NecessaryServices<"API" | "setting", never>, { replicator }: UseP2PReplicatorResult): void; diff --git a/_types/lib/src/replication/trystero/useP2PReplicatorFeature.d.ts b/_types/lib/src/replication/trystero/useP2PReplicatorFeature.d.ts new file mode 100644 index 0000000..f8b95a7 --- /dev/null +++ b/_types/lib/src/replication/trystero/useP2PReplicatorFeature.d.ts @@ -0,0 +1,17 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { LiveSyncTrysteroReplicator } from "./LiveSyncTrysteroReplicator"; +import { type UseP2PReplicatorResult } from "./UseP2PReplicatorResult"; +/** + * Factory type: given a replicator instance, returns the openReplicationUI callback for that instance. + * Injected by the host platform (e.g. Obsidian). CLI/headless environments omit this. + */ +export type OpenReplicationUIFactory = (replicator: LiveSyncTrysteroReplicator) => (showResult: boolean) => Promise; +/** Same shape as OpenReplicationUIFactory, used for the rebuild/replicateAllFromServer flow. */ +export type OpenRebuildUIFactory = OpenReplicationUIFactory; +/** + * ServiceFeature: P2P Replicator integration and lifecycle management. + * Registers a LiveSyncTrysteroReplicator instance as the active replicator when P2P is enabled in settings, + * and binds it to lifecycle events for proper initialization and cleanup. + * @param host + */ +export declare function useP2PReplicatorFeature(host: NecessaryServices<"API" | "setting" | "replicator" | "appLifecycle" | "databaseEvents", never>, openReplicationUIFactory?: OpenReplicationUIFactory, openRebuildUIFactory?: OpenRebuildUIFactory): UseP2PReplicatorResult; diff --git a/_types/lib/src/rpc/RpcRoom.d.ts b/_types/lib/src/rpc/RpcRoom.d.ts new file mode 100644 index 0000000..f96a078 --- /dev/null +++ b/_types/lib/src/rpc/RpcRoom.d.ts @@ -0,0 +1,24 @@ +import { RpcSession } from "./RpcSession"; +import { type JsonLike, type RpcMethodHandler, type RpcRegisterOptions, type RpcRoomOptions } from "./types"; +export declare class RpcRoom { + private options; + private pending; + private inboundCalls; + private methods; + private sessions; + private outgoingChunkMap; + private incomingChunkMap; + private incomingChunkTimers; + private peerVersion; + private disposer; + constructor(options: RpcRoomOptions); + close(): void; + session(peerId: string): RpcSession; + register(method: string, handler: RpcMethodHandler, options?: RpcRegisterOptions): void; + invoke(peerId: string, method: string, args: JsonLike[], timeoutMs?: number): Promise; + cancel(peerId: string, requestId: string): Promise; + private sendEnvelope; + private scheduleMissingAck; + private onWireMessage; + private onEnvelopePayload; +} diff --git a/_types/lib/src/rpc/RpcSession.d.ts b/_types/lib/src/rpc/RpcSession.d.ts new file mode 100644 index 0000000..61ce878 --- /dev/null +++ b/_types/lib/src/rpc/RpcSession.d.ts @@ -0,0 +1,9 @@ +import type { JsonLike } from "./types"; +import type { RpcRoom } from "./RpcRoom"; +export declare class RpcSession { + readonly peerId: string; + private room; + constructor(room: RpcRoom, peerId: string); + call(method: string, args?: JsonLike[], timeoutMs?: number): Promise; + createProxy(namespace: string): T; +} diff --git a/_types/lib/src/rpc/chunking.d.ts b/_types/lib/src/rpc/chunking.d.ts new file mode 100644 index 0000000..326765b --- /dev/null +++ b/_types/lib/src/rpc/chunking.d.ts @@ -0,0 +1,11 @@ +export declare function estimateBytes(text: string): number; +export declare function splitIntoChunks(payload: string, maxBytes: number): string[]; +export declare class IncomingChunkBuffer { + total: number; + parts: Map; + constructor(total: number); + add(index: number, payload: string): void; + missingIndices(): number[]; + isComplete(): boolean; + toPayload(): string; +} diff --git a/_types/lib/src/rpc/errors.d.ts b/_types/lib/src/rpc/errors.d.ts new file mode 100644 index 0000000..265199e --- /dev/null +++ b/_types/lib/src/rpc/errors.d.ts @@ -0,0 +1,8 @@ +import type { JsonLike, RpcErrorCode, RpcErrorShape } from "./types"; +export declare class RpcError extends Error { + code: RpcErrorCode; + details?: JsonLike; + constructor(code: RpcErrorCode, message: string, details?: JsonLike); + toShape(): RpcErrorShape; +} +export declare function asRpcErrorShape(ex: unknown): RpcErrorShape; diff --git a/_types/lib/src/rpc/index.d.ts b/_types/lib/src/rpc/index.d.ts new file mode 100644 index 0000000..54ba92f --- /dev/null +++ b/_types/lib/src/rpc/index.d.ts @@ -0,0 +1,6 @@ +export { RpcRoom } from "./RpcRoom"; +export { RpcSession } from "./RpcSession"; +export { RpcError } from "./errors"; +export { exposeDB } from "./pouchdb/RpcPouchDBServer"; +export { RpcPouchDBProxy } from "./pouchdb/RpcPouchDBProxy"; +export type { JsonLike, RpcEnvelope, RpcErrorCode, RpcErrorShape, RpcMethodHandler, RpcRegisterOptions, RpcRoomOptions, RpcWireMessage, TransportAdapter, } from "./types"; diff --git a/_types/lib/src/rpc/pouchdb/RpcPouchDBProxy.d.ts b/_types/lib/src/rpc/pouchdb/RpcPouchDBProxy.d.ts new file mode 100644 index 0000000..eb0dc6a --- /dev/null +++ b/_types/lib/src/rpc/pouchdb/RpcPouchDBProxy.d.ts @@ -0,0 +1,75 @@ +import EventEmitter from "events"; +import type { RpcSession } from "@lib/rpc/RpcSession"; +/** + * A PouchDB-compatible proxy that forwards all database operations to a remote + * peer via an {@link RpcSession}. + * + * The proxy exposes the same public interface as a PouchDB instance and can be + * passed directly to `PouchDB.replicate()` or `PouchDB.sync()` as either the + * source or the target database. It can also be used with {@link replicateShim} + * from `ReplicatorShim.ts`. + * + * The remote side must have called {@link exposeDB} to register the matching + * RPC handlers. + * + * ### Changes feed + * `changes()` returns an object that satisfies both the EventEmitter interface + * required by `pouchdb-replication` and the Promise interface required by + * `replicateShim` (i.e. it can be `await`ed directly). + * + * ### Error propagation + * PouchDB-specific error properties (`status`, `name`, `reason`) are preserved + * across the RPC transport and reconstructed on the proxy side so that callers + * such as `pouchdb-checkpointer` can inspect `err.status === 404` correctly. + */ +export declare class RpcPouchDBProxy extends EventEmitter { + /** The logical name of the remote database. */ + readonly name: string; + /** + * Stub ActiveTasks object required by `pouchdb-replication`. All + * operations are no-ops; task state is not tracked across the RPC boundary. + */ + readonly activeTasks: { + add: (_task: object) => unknown; + get: (_id: unknown) => unknown; + update: (_id: unknown, _update: object) => void; + remove: (_id: unknown, _err?: Error) => void; + list: () => unknown[]; + }; + private readonly session; + private readonly ns; + constructor(session: RpcSession, name: string, ns?: string); + /** + * Invoke an RPC method and reconstruct PouchDB error shapes on the response. + * + * When the remote handler wraps a PouchDB error via {@link exposeDB}'s + * `runDB` helper, the `RpcError.details` object carries `status`, `name`, + * and `reason`. This method rebuilds a plain `Error` with those properties + * so that callers (e.g. pouchdb-checkpointer) can use `err.status` / + * `err.name` as expected. + */ + private callDB; + info(): Promise; + id(): Promise; + /** + * Returns a `Changes`-compatible object that is simultaneously: + * - An **EventEmitter** with `change`, `complete`, and `error` events, plus + * a `cancel()` method — satisfying the interface consumed by + * `PouchDB.replicate()` / `PouchDB.sync()`. + * - A **thenable** (`then` / `catch`) — allowing `await db.changes(opts)` + * as used by `replicateShim`. + * + * The remote changes feed is always fetched as a one-shot snapshot + * (`live: false`). + */ + changes(opts: PouchDB.Core.ChangesOptions): PouchDB.Core.Changes; + get(id: string, opts?: PouchDB.Core.GetOptions): Promise; + put(doc: PouchDB.Core.PutDocument, opts?: PouchDB.Core.PutOptions): Promise; + bulkGet(opts: PouchDB.Core.BulkGetOptions): Promise>; + bulkDocs(docs: PouchDB.Core.PostDocument[] | { + docs: PouchDB.Core.PostDocument[]; + new_edits?: boolean; + }, opts?: PouchDB.Core.BulkDocsOptions): Promise<(PouchDB.Core.Response | PouchDB.Core.Error)[]>; + revsDiff(diff: PouchDB.Core.RevisionDiffOptions): Promise; + allDocs(opts?: PouchDB.Core.AllDocsOptions): Promise>; +} diff --git a/_types/lib/src/rpc/pouchdb/RpcPouchDBServer.d.ts b/_types/lib/src/rpc/pouchdb/RpcPouchDBServer.d.ts new file mode 100644 index 0000000..3e4dc85 --- /dev/null +++ b/_types/lib/src/rpc/pouchdb/RpcPouchDBServer.d.ts @@ -0,0 +1,16 @@ +import type { RpcRoom } from "@lib/rpc/RpcRoom"; +/** + * Exposes a PouchDB database as a set of RPC methods registered on an + * {@link RpcRoom}. The remote peer can access the database via + * {@link RpcPouchDBProxy}. + * + * All methods are registered under the given namespace prefix `ns` (default: + * `'pdb'`). For example, with the default namespace the method names are + * `pdb.info`, `pdb.id`, `pdb.changes`, `pdb.get`, `pdb.put`, `pdb.bulkGet`, + * `pdb.bulkDocs`, `pdb.revsDiff`, and `pdb.allDocs`. + * + * @param room The {@link RpcRoom} on which to register handlers. + * @param db The PouchDB database instance to expose. + * @param ns Method namespace prefix (default: `'pdb'`). + */ +export declare function exposeDB(room: RpcRoom, db: PouchDB.Database, ns?: string): void; diff --git a/_types/lib/src/rpc/transports/DiagRTCPeerConnections.d.ts b/_types/lib/src/rpc/transports/DiagRTCPeerConnections.d.ts new file mode 100644 index 0000000..95a7e89 --- /dev/null +++ b/_types/lib/src/rpc/transports/DiagRTCPeerConnections.d.ts @@ -0,0 +1,24 @@ +import type { DiagRTCStats, DiagRTCFailureDiagnosis } from "./DiagRTCPeerConnections.types"; +/** + * Subscribes to connection status updates. The callback will be called with the latest connection statistics whenever there is a change in the connection status of any RTCPeerConnection instance. + * Returns an unsubscribe function to stop receiving updates. + * + * @param callback - The function to call with the latest connection statistics. + * @returns A function that can be called to unsubscribe from updates. + */ +export declare function subscribeConnectionStatus(callback: (status: DiagRTCStats) => void): () => void; +/** + * Subscribes to failure diagnosis updates. The callback will be called with the diagnosis information whenever a connection failure is detected in any RTCPeerConnection instance. + * Returns an unsubscribe function to stop receiving updates. + * @param callback - The function to call with the diagnosis information. + * @returns A function that can be called to unsubscribe from updates. + */ +export declare function subscribeFailureDiagnosis(callback: (diagnosis: DiagRTCFailureDiagnosis) => void): () => void; +export type DiagRTCPeerConnectionConstructor = typeof RTCPeerConnection; +/** + * A wrapper around RTCPeerConnection to collect statistics for diagnostics. + * It extends the native (or globally-polyfilled) RTCPeerConnection and overrides its constructor to add event listeners for connection state changes, + * ice connection state changes, ice gathering state changes, and signaling state changes. It maintains a history of these states and logs the progress. + * It also tracks the number of new connections, failed connections, successful connections, and closed connections, and dispatches this information to subscribers. + */ +export declare function createDiagRTCPeerConnectionConstructor(): DiagRTCPeerConnectionConstructor; diff --git a/_types/lib/src/rpc/transports/DiagRTCPeerConnections.types.d.ts b/_types/lib/src/rpc/transports/DiagRTCPeerConnections.types.d.ts new file mode 100644 index 0000000..0fe5ea8 --- /dev/null +++ b/_types/lib/src/rpc/transports/DiagRTCPeerConnections.types.d.ts @@ -0,0 +1,64 @@ +export type DiagRTCConnectionStatus = { + connectionState: RTCPeerConnection["connectionState"]; + iceConnectionState: RTCPeerConnection["iceConnectionState"]; +}; +export type DiagRTCStats = { + totalNewConnections: number; + totalFailedConnections: number; + totalSuccessfulConnections: number; + totalClosedConnections: number; + details: Record; +}; +export type DiagRTCPeerConnectionInternalStateHistory = { + connectionHistory: RTCPeerConnection["connectionState"][]; + iceConnectionHistory: RTCPeerConnection["iceConnectionState"][]; + iceGatheringHistory: RTCPeerConnection["iceGatheringState"][]; + signalingHistory: RTCPeerConnection["signalingState"][]; +}; +export declare const DiagRTCFailureReasonCodes: { + readonly ICE_GATHERING_NOT_COMPLETED: "ICE_GATHERING_NOT_COMPLETED"; + readonly ICE_CONNECTIVITY_FAILED: "ICE_CONNECTIVITY_FAILED"; + readonly STUN_REQUEST_TIMEOUT: "STUN_REQUEST_TIMEOUT"; + readonly SIGNALING_NOT_STABLE: "SIGNALING_NOT_STABLE"; + readonly CONNECTION_DROPPED_AFTER_ESTABLISHED: "CONNECTION_DROPPED_AFTER_ESTABLISHED"; + readonly NETWORK_INTERRUPTED: "NETWORK_INTERRUPTED"; + readonly UNKNOWN: "UNKNOWN"; +}; +export type DiagRTCFailureDiagnosis = { + reasonCode: keyof typeof DiagRTCFailureReasonCodes; + userMessage: string; +}; +export type DiagRTCFailureStats = { + diagnosis: DiagRTCFailureDiagnosis; + stats: { + reportsCount: number; + selectedPair: { + id: string; + state: string; + localCandidateId: string; + remoteCandidateId: string; + currentRoundTripTime: number | "unknown"; + totalRoundTripTime: number | "unknown"; + requestsSent: number | "unknown"; + responsesReceived: number | "unknown"; + packetsDiscardedOnSend: number | "unknown"; + bytesSent: number | "unknown"; + bytesReceived: number | "unknown"; + }; + }; +}; +export type DiagRTCPeerConnectionMetrics = { + selectedPair: Record | undefined; + selectedPairId: string; + state: string; + localCandidateId: string; + remoteCandidateId: string; + currentRoundTripTime: number | "unknown"; + totalRoundTripTime: number | "unknown"; + requestsSent: number | "unknown"; + responsesReceived: number | "unknown"; + packetsDiscardedOnSend: number | "unknown"; + bytesSent: number | "unknown"; + bytesReceived: number | "unknown"; + reports: unknown[]; +}; diff --git a/_types/lib/src/rpc/transports/DiagRTCPeerConnections.utils.d.ts b/_types/lib/src/rpc/transports/DiagRTCPeerConnections.utils.d.ts new file mode 100644 index 0000000..d680767 --- /dev/null +++ b/_types/lib/src/rpc/transports/DiagRTCPeerConnections.utils.d.ts @@ -0,0 +1,33 @@ +import { type DiagRTCPeerConnectionInternalStateHistory, type DiagRTCFailureDiagnosis, type DiagRTCPeerConnectionMetrics, type DiagRTCFailureStats } from "./DiagRTCPeerConnections.types"; +/** + * Diagnoses the failure reason of a failed RTCPeerConnection based on its internal state history and selected candidate pair information. + * @param internalStateHistory The internal state history of the RTCPeerConnection. + * @param selectedPair The selected candidate pair information. + * @returns The diagnosis of the RTC failure. + */ +export declare function diagnoseRtcFailure(internalStateHistory: DiagRTCPeerConnectionInternalStateHistory, selectedPair: Record | undefined): DiagRTCFailureDiagnosis; +/** + * Describes the current progress of the RTCPeerConnection based on its internal state history and selected candidate pair information. + * This is useful for providing user-friendly status messages during the connection process. + * @param internalStateHistory The internal state history of the RTCPeerConnection. + * @param selectedPair The selected candidate pair information. + * @returns A user-friendly description of the current connection progress. + */ +export declare function describeRTCProgress(internalStateHistory: DiagRTCPeerConnectionInternalStateHistory, selectedPair: Record | undefined): string; +/** + * Fetches the RTCPeerConnection statistics and returns a structured metrics object. + * This is useful for diagnosing connection issues and understanding the connection performance. + * @param instanceId An identifier for the RTCPeerConnection instance, used for logging. + * @param peer The RTCPeerConnection instance to fetch stats from. + * @returns A structured object containing the connection metrics, or undefined if fetching stats failed. + */ +export declare function getPeerConnectionStats(instanceId: string, peer: RTCPeerConnection): Promise; +/** + * Audits the RTCPeerConnection for failures and returns a structured failure report. + * This is useful for diagnosing connection issues and understanding the reasons for failure. + * @param instanceId An identifier for the RTCPeerConnection instance, used for logging. + * @param internalStateHistory The internal state history of the RTCPeerConnection. + * @param peer The RTCPeerConnection instance to audit. + * @returns A structured object containing the failure diagnosis and metrics, or undefined if auditing failed. + */ +export declare function auditRtcConnectionFailures(instanceId: string, internalStateHistory: DiagRTCPeerConnectionInternalStateHistory, peer: RTCPeerConnection): Promise; diff --git a/_types/lib/src/rpc/transports/TrysteroTransport.d.ts b/_types/lib/src/rpc/transports/TrysteroTransport.d.ts new file mode 100644 index 0000000..f697998 --- /dev/null +++ b/_types/lib/src/rpc/transports/TrysteroTransport.d.ts @@ -0,0 +1,216 @@ +import { type Room } from "@trystero-p2p/nostr"; +import { RpcRoom } from "@lib/rpc/RpcRoom"; +import { RpcPouchDBProxy } from "@lib/rpc/pouchdb/RpcPouchDBProxy"; +import type { RpcRoomOptions, TransportAdapter } from "@lib/rpc/types"; +import type { P2PConnectionInfo } from "@lib/common/models/setting.type"; +/** + * Lightweight presence record broadcast by each peer when it joins the room. + * The `peerId` field MUST match the Trystero sender ID to prevent spoofing. + */ +export type TrysteroAdvertisement = { + /** The Trystero `selfId` of the sending peer. */ + peerId: string; + /** Human-readable device / vault name. */ + name: string; + /** Optional platform tag (e.g. `"desktop"`, `"mobile"`). */ + platform: string; +}; +/** The handle returned by {@link attachAdvertisement}. */ +export type AdvertisementHandle = { + /** + * All currently known peers, keyed by `peerId`. + * Updated in real-time as advertisements arrive or peers leave. + */ + readonly peers: ReadonlyMap; + /** + * (Re-)broadcast your own advertisement. + * Pass a `toPeerId` to send only to that peer; omit to broadcast to all. + */ + sendAdvertisement(toPeerId?: string): Promise; + /** Stop listening for advertisements and clear the peer map. */ + stop(): void; +}; +/** + * Attach advertisement-based peer discovery to an already-joined Trystero room. + * + * - Sends your advertisement to every peer that joins after this call. + * - Stores incoming advertisements in `handle.peers`. + * - Removes entries when peers leave. + * + * @param room An active Trystero room. + * @param localPeerId Your own Trystero `selfId`. + * @param name Human-readable name broadcast to other peers. + * @param platform Optional platform string (default `"unknown"`). + */ +export declare function attachAdvertisement(room: Room, localPeerId: string, name: string, platform?: string): AdvertisementHandle; +/** + * Options forwarded to the `RpcRoom` constructor when creating a room through + * the high-level helpers (`serveTrysteroDB`, `connectTrysteroDBClient`, or by + * calling `joinTrysteroRoom` and then constructing `RpcRoom` manually). + * + * Trystero internally chunks at ~16 348 bytes (16 KiB minus a 36-byte header). + * Setting `maxWirePayloadBytes` above that threshold causes double-chunking. + * The Trystero-appropriate default is therefore **15 360 bytes** (15 KiB), + * which leaves ~1 KiB of headroom for the JSON wrapper overhead. + * + * Trystero uses WebRTC SCTP data channels which guarantee delivery and order, + * so missing-chunk retransmission virtually never triggers. `chunkMissingRetryMs` + * can safely be lowered from the generic default of 350 ms to **150 ms**. + */ +export type TrysteroRoomOptions = Pick & { + maxWirePayloadBytes?: number; + chunkMissingRetryMs?: number; +}; +/** Trystero-appropriate defaults for `RpcRoom`. */ +export declare const TRYSTERO_RPC_DEFAULTS: { + /** Stay below Trystero's internal ~16 348-byte chunk boundary. */ + readonly maxWirePayloadBytes: number; + /** SCTP guarantees delivery; retransmission is a last-resort safety net. */ + readonly chunkMissingRetryMs: 150; +}; +/** + * Wrap an already-joined Trystero `Room` as a `TransportAdapter` for `RpcRoom`. + * + * A dedicated Trystero action channel named `"rpc2"` is created on the room. + * Note: Trystero does not expose per-handler unsubscription for `onPeerJoin` + * / `onPeerLeave`, so the returned cleanup stubs are no-ops. Close the + * Trystero room via `leave()` when done. + * + * @param room An active Trystero `Room` returned by `joinRoom()`. + * @returns A `TransportAdapter` that can be passed to `new RpcRoom(...)`. + */ +export declare function wrapTrysteroRoom(room: Room): TransportAdapter; +/** The result of joining a Trystero room. */ +export type TrysteroRoomHandle = { + /** `TransportAdapter` ready to pass to `new RpcRoom(...)`. */ + transport: TransportAdapter; + /** This peer's own ID (Trystero `selfId`). */ + peerId: string; + /** Leave the Trystero room and release resources. */ + leave: () => Promise; + /** + * Attach advertisement-based peer discovery to this room. + * Call once after joining; returns a handle to read and re-broadcast. + */ + advertise: (name: string, platform?: string) => AdvertisementHandle; + /** + * Returns the current WebRTC peer connections keyed by peer ID. + * Equivalent to the Trystero `room.getPeers()` call. + */ + getPeers: () => Record; + /** + * The underlying Trystero `Room` instance. + * Use when you need raw access to Trystero APIs such as `makeAction`, + * `onPeerJoin`, or `onPeerLeave` beyond what the helpers expose. + */ + room: Room; +}; +/** + * Join a Trystero room from a {@link P2PConnectionInfo} and return a + * `TransportAdapter` together with this peer's own ID. + * + * The raw passphrase is hashed with `mixedHash` before being passed to + * Trystero, matching the convention used by `TrysteroReplicatorP2PServer`. + */ +export declare function joinTrysteroRoom(settings: P2PConnectionInfo): TrysteroRoomHandle; +/** + * Join a Trystero room from a `sls+p2p://` connection string and return a + * `TransportAdapter` together with this peer's own ID. + * + * The URL must be parseable by {@link ConnectionStringParser.parse} as type + * `"p2p"`, i.e. it must start with `sls+p2p://`. + * + * @example + * ```ts + * const handle = joinTrysteroRoomFromUrl( + * "sls+p2p://my-room?relays=wss://relay.example.com&appId=my-app" + * ); + * const rpcRoom = new RpcRoom({ transport: handle.transport }); + * ``` + */ +export declare function joinTrysteroRoomFromUrl(url: string): TrysteroRoomHandle; +/** The result of starting a DB server over Trystero. */ +export type TrysteroDBServerHandle = { + /** This peer's own ID. Share it with clients so they can call `session()`. */ + peerId: string; + /** The `RpcRoom` that hosts the DB methods. */ + rpcRoom: RpcRoom; + /** Stop serving and leave the room. */ + close: () => Promise; + /** + * Attach advertisement-based peer discovery so that clients can find this + * server without needing the peerId passed out-of-band. + */ + advertise: (name: string, platform?: string) => AdvertisementHandle; +}; +/** + * **Server side.** Join a Trystero room and expose `db` as a set of RPC + * methods. The caller's `peerId` is returned so that it can be shared with + * clients (e.g. via a separate signalling channel or advertisement). + * + * @param settings P2P connection settings (from `P2PConnectionInfo` or parsed + * from a `sls+p2p://` URL via {@link ConnectionStringParser}). + * @param db The PouchDB database to expose. + * @param ns Method namespace (default `"pdb"`). + * + * @example + * ```ts + * const server = serveTrysteroDB(settings, db); + * console.log("server peer ID:", server.peerId); + * // Share server.peerId with the client out-of-band. + * ``` + */ +export declare function serveTrysteroDB(settings: P2PConnectionInfo, db: PouchDB.Database, ns?: string, options?: TrysteroRoomOptions): TrysteroDBServerHandle; +/** The result of connecting to a DB server over Trystero. */ +export type TrysteroDBClientHandle = { + /** Proxy object usable with `PouchDB.replicate()` or `replicateShim()`. */ + proxy: RpcPouchDBProxy; + /** The `RpcRoom` used to communicate with the server. */ + rpcRoom: RpcRoom; + /** Disconnect and leave the room. */ + close: () => Promise; + /** + * Attach advertisement-based peer discovery so this client can locate the + * server peer without needing its peerId passed statically. + */ + advertise: (name: string, platform?: string) => AdvertisementHandle; +}; +/** + * **Client side.** Join a Trystero room and create an {@link RpcPouchDBProxy} + * pointing at `serverPeerId`. The proxy can be passed directly to + * `PouchDB.replicate()` or `replicateShim()`. + * + * @param settings P2P connection settings. + * @param serverPeerId The `peerId` of the server peer (returned by + * {@link serveTrysteroDB}). + * @param dbName Logical name for the remote database. + * @param ns Method namespace, must match the server's `ns` + * (default `"pdb"`). + * + * @example + * ```ts + * const client = connectTrysteroDBClient(settings, serverPeerId, "my-db"); + * await PouchDB.replicate(client.proxy, localDb, { live: false }); + * await client.close(); + * ``` + */ +export declare function connectTrysteroDBClient(settings: P2PConnectionInfo, serverPeerId: string, dbName: string, ns?: string, options?: TrysteroRoomOptions): TrysteroDBClientHandle; +/** + * Join a Trystero room, advertise as `name`, wait `timeoutMs`, collect all + * received peer advertisements, then leave the room and return the results. + * + * Useful for CLI-style peer discovery where you need a one-shot list of + * present peers before deciding how to connect. + * + * @param settings P2P connection settings. + * @param name Your local device / vault name advertised to others. + * @param timeoutMs How long to listen before returning (milliseconds). + * @param platform Optional platform tag (default `"unknown"`). + * + * @example + * ```ts + * const peers = await collectTrysteroAdvertisements(settings, "my-vault", 5000); + * console.log(peers.map(p => `${p.name} (${p.peerId})`)); + * ``` + */ +export declare function collectTrysteroAdvertisements(settings: P2PConnectionInfo, name: string, timeoutMs: number, platform?: string): Promise; diff --git a/_types/lib/src/rpc/transports/trysteroUtils.d.ts b/_types/lib/src/rpc/transports/trysteroUtils.d.ts new file mode 100644 index 0000000..328e488 --- /dev/null +++ b/_types/lib/src/rpc/transports/trysteroUtils.d.ts @@ -0,0 +1,3 @@ +import type { BaseRoomConfig } from "@trystero-p2p/nostr"; +import type { P2PConnectionInfo } from "@lib/common/models/setting.type"; +export declare function generateJoinRoomOptions(settings: P2PConnectionInfo): BaseRoomConfig; diff --git a/_types/lib/src/rpc/types.d.ts b/_types/lib/src/rpc/types.d.ts new file mode 100644 index 0000000..7577c33 --- /dev/null +++ b/_types/lib/src/rpc/types.d.ts @@ -0,0 +1,75 @@ +export declare const RPC_VERSION_MAJOR = 1; +export declare const RPC_VERSION_MINOR = 0; +export type JsonLike = null | boolean | number | string | JsonLike[] | { + [key: string]: JsonLike; +}; +export type RpcErrorCode = "TIMEOUT" | "NOT_CONNECTED" | "REMOTE_ERROR" | "CANCELLED" | "PROTOCOL_ERROR"; +export type RpcErrorShape = { + code: RpcErrorCode; + message: string; + details?: JsonLike; +}; +export type RpcRequestEnvelope = { + kind: "request"; + requestId: string; + method: string; + args: JsonLike[]; +}; +export type RpcResponseEnvelope = { + kind: "response"; + requestId: string; + ok: true; + data: JsonLike; +}; +export type RpcResponseErrorEnvelope = { + kind: "response"; + requestId: string; + ok: false; + error: RpcErrorShape; +}; +export type RpcCancelEnvelope = { + kind: "cancel"; + requestId: string; +}; +export type RpcHandshakeEnvelope = { + kind: "handshake"; + versionMajor: number; + versionMinor: number; +}; +export type RpcEnvelope = RpcRequestEnvelope | RpcResponseEnvelope | RpcResponseErrorEnvelope | RpcCancelEnvelope | RpcHandshakeEnvelope; +export type RpcWireMessageRaw = { + wire: "raw"; + payload: string; +}; +export type RpcWireMessageChunk = { + wire: "chunk"; + streamId: string; + index: number; + total: number; + payload: string; +}; +export type RpcWireMessageChunkAck = { + wire: "chunk-ack"; + streamId: string; + missing: number[]; +}; +export type RpcWireMessage = RpcWireMessageRaw | RpcWireMessageChunk | RpcWireMessageChunkAck; +export type TransportOnMessage = (message: RpcWireMessage, peerId: string) => void; +export type TransportOnPeer = (peerId: string) => void; +export interface TransportAdapter { + send(message: RpcWireMessage, peerId: string): void | Promise; + onMessage(handler: TransportOnMessage): () => void; + onPeerJoin?(handler: TransportOnPeer): () => void; + onPeerLeave?(handler: TransportOnPeer): () => void; +} +export type RpcRoomOptions = { + transport: TransportAdapter; + maxWirePayloadBytes?: number; + chunkMissingRetryMs?: number; + canAcceptRequest?: (peerId: string, method: string) => boolean | Promise; + onProtocolWarning?: (message: string, peerId?: string) => void; +}; +export type RpcMethodHandler = (peerId: string, ...args: T) => U | Promise; +export type RpcRegisterOptions = { + serial?: boolean; +}; diff --git a/_types/lib/src/serviceFeatures/checkRemoteSize.d.ts b/_types/lib/src/serviceFeatures/checkRemoteSize.d.ts new file mode 100644 index 0000000..b6bfa5f --- /dev/null +++ b/_types/lib/src/serviceFeatures/checkRemoteSize.d.ts @@ -0,0 +1,28 @@ +import { createInstanceLogFunction, type LogFunction } from "@lib/services/lib/logUtils"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +/** + * Notify when checking remote storage size is not configured. + * @returns true if the check is passed or user has configured the notification, false to block subsequent processes. (always true). + */ +export declare function onNotifyRemoteSizeNotConfiguredFactory(host: NecessaryServices<"appLifecycle" | "API" | "setting", never>, log: ReturnType): () => Promise; +/** + * Notify when the remote storage size exceed the threshold. + * @returns true if the check is passed or user has chosen to ignore the warning, false to block subsequent processes. + * @param host + * @param log + * @returns + */ +export declare function onNotifyRemoteSizeExceedFactory(host: NecessaryServices<"API" | "setting" | "replicator", "rebuilder">, log: ReturnType): () => Promise; +/** + * Scan the remote storage size and notify if it is not configured or exceed the threshold. + * @param host The necessary services required for the operation. + * @param log The logging function to use for logging messages. + * @param resetThreshold Whether to reset the notification threshold before scanning. This is useful when you want to force the notification to show up again. + * @returns A promise that resolves to true if all checks pass or user has configured the notification. + */ +export declare function scanAllStat(host: NecessaryServices<"API" | "setting" | "replicator" | "appLifecycle", "rebuilder">, log: LogFunction, resetThreshold?: boolean): Promise; +/** + * Associate the remote storage size check feature with the app lifecycle events. + * @param host + */ +export declare function useCheckRemoteSize(host: NecessaryServices<"API" | "setting" | "replicator" | "appLifecycle", "rebuilder">): void; diff --git a/_types/lib/src/serviceFeatures/offlineScanner.d.ts b/_types/lib/src/serviceFeatures/offlineScanner.d.ts new file mode 100644 index 0000000..53de626 --- /dev/null +++ b/_types/lib/src/serviceFeatures/offlineScanner.d.ts @@ -0,0 +1,131 @@ +import type { LOG_LEVEL } from "@lib/common/logger"; +import type { FilePathWithPrefix, FilePathWithPrefixLC, MetaEntry } from "@lib/common/models/db.type"; +import type { UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { UnresolvedErrorManager } from "@lib/services/base/UnresolvedErrorManager"; +/** + * Collect deleted files that have expired according to retention policy. + * @param host Services container + * @param log Logging function + * @returns Array of expired deletion history + */ +export declare function collectDeletedFiles(host: NecessaryServices<"setting" | "database", never>, log: LogFunction): Promise; +/** + * Get the file path from a meta entry. + * This is a helper function to extract path from various document types. + * @param doc Meta entry document + * @returns Path string + */ +export declare function getPathFromEntry(host: NecessaryServices<"path", never>, doc: MetaEntry): FilePathWithPrefix; +/** + * Synchronise a single file between database and storage based on freshness comparison. + * @param host Services container + * @param log Logging function + * @param file Storage file information + * @param doc Database entry + */ +export declare function syncFileBetweenDBandStorage(host: NecessaryServices<"setting" | "vault" | "path", "storageAccess" | "fileHandler">, log: LogFunction, file: UXFileInfoStub, doc: MetaEntry): Promise; +export declare function canProceedScan(host: NecessaryServices<"keyValueDB" | "setting", never>, errorManager: UnresolvedErrorManager, log: LogFunction, showingNotice?: boolean, ignoreSuspending?: boolean): boolean; +/** + * Convert file path to lower case if the settings indicate that filename case should be handled insensitively. + * @param settings + * @param path + * @returns + */ +export declare function convertCase(settings: ObsidianLiveSyncSettings, path: T): FilePathWithPrefixLC; +export declare function collectFilesOnStorage(host: NecessaryServices<"vault", "storageAccess">, settings: ObsidianLiveSyncSettings, log: LogFunction): Promise<{ + storageFileNameMap: { + [k: string]: UXFileInfoStub; + }; + storageFileNames: FilePathWithPrefix[]; + storageFileNameCI2CS: Record; +}>; +export declare function collectDatabaseFiles(host: NecessaryServices<"database" | "vault" | "path", never>, settings: ObsidianLiveSyncSettings, log: LogFunction, showingNotice: boolean): Promise<{ + databaseFileNameMap: { + [k: string]: MetaEntry; + }; + databaseFileNames: FilePathWithPrefix[]; + databaseFileNameCI2CS: Record; +}>; +export declare function updateToDatabase(host: NecessaryServices<"vault", "fileHandler">, log: LogFunction, logLevel: LOG_LEVEL, file: UXFileInfoStub): Promise; +export declare function updateToStorage(host: NecessaryServices<"vault" | "path", "fileHandler">, log: LogFunction, logLevel: LOG_LEVEL, w: MetaEntry): Promise; +export declare function syncStorageAndDatabase(host: NecessaryServices<"setting" | "vault" | "path", "storageAccess" | "fileHandler">, log: LogFunction, file: UXFileInfoStub, logLevel: LOG_LEVEL, doc: MetaEntry): Promise; +export declare const FullScanModes: { + readonly DB_APPLY: "db-apply"; + readonly NEWER_WINS: "newer-wins"; +}; +export declare const ExtraOnRemote: { + /** + * Delete database entries if they are missing on storage. + */ + readonly DELETE_LOCAL_MISSING: "delete-local-missing"; +}; +export declare const ExtraOnLocal: { + /** + * Delete local files if they were deleted on database. + */ + readonly DELETE_DB_DELETED: "delete-db-deleted"; + /** + * Delete local files if they are missing on database or were deleted on database. + */ + readonly DELETE_DB_MISSING: "delete-db-missing"; + /** + * Merge local files to database + */ + readonly APPEND_STORAGE_ONLY: "append-storage-only"; +}; +export interface FullScanOptions { + mode: FullScanMode; + extraOnLocal?: (typeof ExtraOnLocal)[keyof typeof ExtraOnLocal]; + extraOnRemote?: (typeof ExtraOnRemote)[keyof typeof ExtraOnRemote]; + omitEvents?: boolean; + showingNotice?: boolean; + ignoreSuspending?: boolean; +} +export type FullScanMode = (typeof FullScanModes)[keyof typeof FullScanModes]; +type FilePair = { + file: UXFileInfoStub; + doc: MetaEntry; +} | { + file: undefined; + doc: MetaEntry; +} | { + file: UXFileInfoStub; + doc: undefined; +}; +type FilePairState = "storage-only" | "db-only" | "db-only-deleted" | "both" | "both-db-deleted"; +type FilePairAction = "update-db" | "update-storage" | "sync-newer" | "delete-local" | "delete-db" | "skip"; +export declare function getFilePairState(pair: FilePair): FilePairState; +/** + * Determine the action to be taken for a file pair based on its state and the selected scan options. + */ +export declare function resolveFilePairAction(state: FilePairState, options: FullScanOptions): FilePairAction; +/** + * Synchronise all files between database and storage based on the selected mode and options. + * @param host Core + * @param log Logging function + * @param errorManager Error manager + * @param options Full scan options + */ +export declare function synchroniseAllFilesBetweenDBandStorage(host: NecessaryServices<"setting" | "vault" | "path" | "fileProcessing" | "database" | "keyValueDB", "storageAccess" | "fileHandler">, log: LogFunction, errorManager: UnresolvedErrorManager, options: FullScanOptions): Promise; +export declare function normaliseFullScanOptions(showingNoticeOrOptions: Partial | boolean | undefined, ignoreSuspending?: boolean): FullScanOptions; +/** + * Perform a full scan and synchronisation between database and storage. + * @param host Services container + * @param log Logging function + * @param errorManager Error manager + * @param showingNotice Whether to show notices during scanning + * @param ignoreSuspending Whether to ignore suspension settings + * @returns True if scan completed successfully + */ +export declare function performFullScan(host: NecessaryServices<"setting" | "vault" | "path" | "fileProcessing" | "database" | "keyValueDB", "storageAccess" | "fileHandler">, log: LogFunction, errorManager: UnresolvedErrorManager, options?: Partial): Promise; +export declare function performFullScan(host: NecessaryServices<"setting" | "vault" | "path" | "fileProcessing" | "database" | "keyValueDB", "storageAccess" | "fileHandler">, log: LogFunction, errorManager: UnresolvedErrorManager, showingNotice?: boolean, ignoreSuspending?: boolean): Promise; +/** + * Associate the initialiser file feature with the app lifecycle events. + * This function binds initialization handlers to the appropriate lifecycle events. + * @param host Services container with required dependencies + */ +export declare function useOfflineScanner(host: NecessaryServices<"API" | "appLifecycle" | "setting" | "vault" | "path" | "database" | "databaseEvents" | "fileProcessing" | "keyValueDB" | "replicator", "storageAccess" | "fileHandler">): void; +export {}; diff --git a/_types/lib/src/serviceFeatures/prepareDatabaseForUse.d.ts b/_types/lib/src/serviceFeatures/prepareDatabaseForUse.d.ts new file mode 100644 index 0000000..d89ccf5 --- /dev/null +++ b/_types/lib/src/serviceFeatures/prepareDatabaseForUse.d.ts @@ -0,0 +1,20 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { UnresolvedErrorManager } from "@lib/services/base/UnresolvedErrorManager"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +/** + * Initialise the database and trigger a full vault scan. + * @param host Services container + * @param log Logging function + * @param errorManager Error manager + * @param showingNotice Whether to show notices during initialisation + * @param reopenDatabase Whether to reopen the database connection + * @param ignoreSuspending Whether to ignore suspension settings + * @returns True if initialisation succeeded + */ +export declare function prepareDatabaseForUse(host: NecessaryServices<"appLifecycle" | "setting" | "vault" | "path" | "database" | "databaseEvents" | "fileProcessing" | "replicator", never>, log: LogFunction, errorManager: UnresolvedErrorManager, showingNotice?: boolean, reopenDatabase?: boolean, ignoreSuspending?: boolean): Promise; +/** + * Associate the initialiser file feature with the app lifecycle events. + * This function binds initialization handlers to the appropriate lifecycle events. + * @param host Services container with required dependencies + */ +export declare function usePrepareDatabaseForUse(host: NecessaryServices<"API" | "appLifecycle" | "setting" | "vault" | "path" | "database" | "databaseEvents" | "fileProcessing" | "replicator", never>): void; diff --git a/_types/lib/src/serviceFeatures/remoteConfig.d.ts b/_types/lib/src/serviceFeatures/remoteConfig.d.ts new file mode 100644 index 0000000..39d8308 --- /dev/null +++ b/_types/lib/src/serviceFeatures/remoteConfig.d.ts @@ -0,0 +1,46 @@ +import { type LOG_LEVEL } from "@lib/common/logger"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +export type RemoteConfigHost = NecessaryServices<"setting" | "UI" | "replication" | "control" | "appLifecycle" | "API", never>; +export declare function migrateLegacyRemoteConfigurationsInPlace(settings: ObsidianLiveSyncSettings, log?: (message: string, level?: LOG_LEVEL) => void): boolean; +/** + * Generate a unique ID for a new remote configuration. + * @returns A unique string identifier. + */ +export declare function createRemoteConfigurationId(): string; +/** + * Keep compatibility for users who were already using P2P as their main active remote. + */ +export declare function migrateP2PActiveRemoteConfigurationIdInPlace(settings: ObsidianLiveSyncSettings): boolean; +/** + * SF:RemoteConfig - Service Feature for Remote Configuration Management + */ +/** + * Migrates existing flat settings to the new multiple remote configurations list. + */ +export declare function migrateToMultipleRemoteConfigurations(host: RemoteConfigHost): Promise; +/** + * Logic to switch the active configuration. + */ +export declare function activateRemoteConfiguration(settings: ObsidianLiveSyncSettings, id: string): ObsidianLiveSyncSettings | false; +/** + * Apply a dedicated P2P remote configuration onto runtime P2P-related fields, + * while keeping the current `remoteType` unchanged. + */ +export declare function activateP2PRemoteConfiguration(settings: ObsidianLiveSyncSettings, id: string): ObsidianLiveSyncSettings | false; +/** + * Command: Switch Active Remote + */ +export declare function commandSwitchActiveRemote(host: RemoteConfigHost): Promise; +/** + * Command: Replicate with specific remote + */ +export declare function commandReplicateWithSpecificRemote(host: RemoteConfigHost): Promise; +/** + * Migration feature to be used during initialisation. + */ +export declare function useRemoteConfigurationMigration(host: RemoteConfigHost): void; +/** + * Hook to set up remote configuration features (Commands). + */ +export declare function useRemoteConfiguration(host: RemoteConfigHost): boolean; diff --git a/_types/lib/src/serviceFeatures/setupObsidian/qrCode.d.ts b/_types/lib/src/serviceFeatures/setupObsidian/qrCode.d.ts new file mode 100644 index 0000000..c13147d --- /dev/null +++ b/_types/lib/src/serviceFeatures/setupObsidian/qrCode.d.ts @@ -0,0 +1,4 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import type { SetupFeatureHost } from "./types"; +export declare function encodeSetupSettingsAsQR(host: SetupFeatureHost): Promise; +export declare function useSetupQRCodeFeature(host: NecessaryServices<"API" | "UI" | "setting" | "appLifecycle", never>): void; diff --git a/_types/lib/src/serviceFeatures/setupObsidian/setupUri.d.ts b/_types/lib/src/serviceFeatures/setupObsidian/setupUri.d.ts new file mode 100644 index 0000000..aee3268 --- /dev/null +++ b/_types/lib/src/serviceFeatures/setupObsidian/setupUri.d.ts @@ -0,0 +1,7 @@ +import type { LogFunction } from "@lib/services/lib/logUtils"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import type { SetupFeatureHost } from "./types"; +export declare function askEncryptingPassphrase(host: SetupFeatureHost): Promise; +export declare function copySetupURI(host: SetupFeatureHost, log: LogFunction, stripExtra?: boolean): Promise; +export declare function copySetupURIFull(host: SetupFeatureHost, log: LogFunction): Promise; +export declare function useSetupURIFeature(host: NecessaryServices<"API" | "UI" | "setting" | "appLifecycle", never>): void; diff --git a/_types/lib/src/serviceFeatures/setupObsidian/types.d.ts b/_types/lib/src/serviceFeatures/setupObsidian/types.d.ts new file mode 100644 index 0000000..1faedfa --- /dev/null +++ b/_types/lib/src/serviceFeatures/setupObsidian/types.d.ts @@ -0,0 +1,2 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +export type SetupFeatureHost = NecessaryServices<"API" | "UI" | "setting", never>; diff --git a/_types/lib/src/serviceFeatures/targetFilter.d.ts b/_types/lib/src/serviceFeatures/targetFilter.d.ts new file mode 100644 index 0000000..80f5101 --- /dev/null +++ b/_types/lib/src/serviceFeatures/targetFilter.d.ts @@ -0,0 +1,24 @@ +import type { UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +/** + * This is a simple handler that accepts all files. + */ +export declare function isAcceptedAlwaysFactory(host: NecessaryServices, log: LogFunction): (file: string | UXFileInfoStub) => Promise; +/** + * Check if a file is accepted based on filename duplication in the vault. + */ +export declare function isAcceptedInFilenameDuplicationFactory(host: NecessaryServices<"vault" | "fileProcessing", "storageAccess">, log: LogFunction): (file: string | UXFileInfoStub) => Promise; +/** + * Check if a file is accepted by the local database (e.g., not rejected by the local DB's target file check). + * Local database responsible for non-internal files, syncOnlyRegEx, syncIgnoreRegEx + * This possibly should be separated. + */ +export declare function isAcceptedByLocalDBFactory(host: NecessaryServices<"database" | "databaseEvents", never>, log: LogFunction): (file: string | UXFileInfoStub) => Promise; +/** + * Factory function to create the isAcceptedByIgnoreFiles handler. + * This handler checks if a file is ignored based on the ignore files specified in the settings. + * It also caches the ignore file contents for performance and listens to settings changes to invalidate the cache. + */ +export declare function isAcceptedByIgnoreFilesFactory(host: NecessaryServices<"setting" | "appLifecycle", "storageAccess">, log: LogFunction): (file: string | UXFileInfoStub) => Promise; +export declare function useTargetFilters(host: NecessaryServices<"API" | "vault" | "fileProcessing" | "setting" | "appLifecycle" | "database" | "databaseEvents", "storageAccess">): void; diff --git a/_types/lib/src/serviceModules/FileAccessBase.d.ts b/_types/lib/src/serviceModules/FileAccessBase.d.ts new file mode 100644 index 0000000..ae1f45b --- /dev/null +++ b/_types/lib/src/serviceModules/FileAccessBase.d.ts @@ -0,0 +1,93 @@ +import type { FilePath } from "@lib/common/models/db.type"; +import type { UXDataWriteOptions, UXFileInfoStub, UXFolderInfo } from "@lib/common/models/fileaccess.type"; +import type { IStorageAccessManager } from "@lib/interfaces/StorageAccess.ts"; +import type { IAPIService, IPathService, ISettingService, IVaultService } from "@lib/services/base/IService.ts"; +import { createInstanceLogFunction } from "@lib/services/lib/logUtils.ts"; +import type { FileWithFileStat } from "@lib/common/models/fileaccess.type"; +import type { IFileSystemAdapter } from "./adapters"; +export declare function toArrayBuffer(arr: Uint8Array | ArrayBuffer | DataView): ArrayBuffer; +export interface FileAccessBaseDependencies { + vaultService: IVaultService; + storageAccessManager: IStorageAccessManager; + settingService: ISettingService; + pathService: IPathService; + APIService: IAPIService; +} +/** + * Type helper to extract the abstract file type from a file system adapter + */ +export type ExtractAbstractFile = T extends IFileSystemAdapter ? A : never; +/** + * Type helper to extract the file type from a file system adapter + */ +export type ExtractFile = T extends IFileSystemAdapter ? F : never; +/** + * Type helper to extract the folder type from a file system adapter + */ +export type ExtractFolder = T extends IFileSystemAdapter ? D : never; +/** + * Type helper to extract the stat type from a file system adapter + */ +export type ExtractStat = T extends IFileSystemAdapter ? S : never; +/** + * Base class for file access operations + * Uses adapter pattern for platform-specific implementations + * + * @template TAdapter - The file system adapter type, which determines all native file types + */ +export declare class FileAccessBase> { + protected storageAccessManager: IStorageAccessManager; + protected vaultService: IVaultService; + protected settingService: ISettingService; + protected APIService: IAPIService; + protected path: IPathService; + protected adapter: TAdapter; + _log: ReturnType; + constructor(adapter: TAdapter, dependencies: FileAccessBaseDependencies); + isFile(file: UXFileInfoStub | ExtractAbstractFile | FilePath | ExtractFolder | ExtractFile | null): file is ExtractFile; + isFolder(item: UXFileInfoStub | ExtractAbstractFile | FilePath | ExtractFolder | ExtractFile | null): item is ExtractFolder; + getPath(file: ExtractAbstractFile | string): FilePath; + nativeFileToUXFileInfoStub(file: ExtractFile): UXFileInfoStub; + nativeFolderToUXFolder(file: ExtractFolder): UXFolderInfo; + normalisePath(path: string): string; + protected _writeOp | string, U>(file: T, callback: (path: FilePath, file: T) => Promise): Promise; + protected _readOp | string, U>(file: T, callback: (path: FilePath, file: T) => Promise): Promise; + tryAdapterStat(file: ExtractFile | string): Promise; + adapterStat(file: ExtractFile | string): Promise | null>; + adapterExists(file: ExtractFile | string): Promise; + adapterRemove(file: ExtractFile | string): Promise; + adapterRead(file: ExtractFile | string): Promise; + adapterReadBinary(file: ExtractFile | string): Promise; + adapterReadAuto(file: ExtractFile | string): Promise; + adapterWrite(file: ExtractFile | string, data: string | ArrayBuffer | Uint8Array, options?: UXDataWriteOptions): Promise; + adapterList(basePath: string): Promise<{ + files: string[]; + folders: string[]; + }>; + vaultCacheRead(file: ExtractFile): Promise; + vaultRead(file: ExtractFile): Promise; + vaultReadBinary(file: ExtractFile): Promise; + vaultReadAuto(file: ExtractFile): Promise; + vaultModify(file: ExtractFile, data: string | ArrayBuffer | Uint8Array, options?: UXDataWriteOptions): Promise; + vaultCreate(path: string, data: string | ArrayBuffer | Uint8Array, options?: UXDataWriteOptions): Promise>; + trigger(name: string, ...data: any[]): any; + reconcileInternalFile(path: string): Promise; + /** + * Append data to a file using the adapter's append method. This is useful for large files that cannot be read into memory. + * Please note that this method does not check concurrent modifications. + * @param normalizedPath + * @param data + * @param options + * @returns + */ + adapterAppend(normalizedPath: string, data: string, options?: UXDataWriteOptions): Promise; + delete(file: ExtractAbstractFile | ExtractFolder, force?: boolean): Promise; + trash(file: ExtractAbstractFile | ExtractFolder, force?: boolean): Promise; + protected isStorageInsensitive(): boolean; + getAbstractFileByPath(path: FilePath | string): Promise | null>; + getFiles(): Promise[]>; + ensureDirectory(fullPath: string): Promise; + touch(file: ExtractFile | FilePath): Promise; + recentlyTouched(file: ExtractFile | UXFileInfoStub | FileWithFileStat): boolean; + clearTouched(): void; +} diff --git a/_types/lib/src/serviceModules/Rebuilder.d.ts b/_types/lib/src/serviceModules/Rebuilder.d.ts new file mode 100644 index 0000000..e201d87 --- /dev/null +++ b/_types/lib/src/serviceModules/Rebuilder.d.ts @@ -0,0 +1,82 @@ +import type { IFileHandler } from "@lib/interfaces/FileHandler"; +import type { APIService } from "@lib/services/base/APIService"; +import type { AppLifecycleService } from "@lib/services/base/AppLifecycleService"; +import type { DatabaseEventService } from "@lib/services/base/DatabaseEventService"; +import type { DatabaseService } from "@lib/services/base/DatabaseService"; +import type { RemoteService } from "@lib/services/base/RemoteService"; +import type { ReplicationService } from "@lib/services/base/ReplicationService"; +import type { ReplicatorService } from "@lib/services/base/ReplicatorService"; +import type { SettingService } from "@lib/services/base/SettingService"; +import type { VaultService } from "@lib/services/base/VaultService"; +import type { UIService } from "@lib/services/implements/base/UIService"; +import type { Rebuilder } from "@lib/interfaces/DatabaseRebuilder"; +import type { StorageAccess } from "@lib/interfaces/StorageAccess"; +import { ServiceModuleBase } from "./ServiceModuleBase"; +import type { ControlService } from "@lib/services/base/ControlService"; +export interface ServiceRebuilderDependencies { + appLifecycle: AppLifecycleService; + API: APIService; + UI: UIService; + setting: SettingService; + remote: RemoteService; + databaseEvents: DatabaseEventService; + storageAccess: StorageAccess; + replicator: ReplicatorService; + vault: VaultService; + replication: ReplicationService; + database: DatabaseService; + fileHandler: IFileHandler; + control: ControlService; +} +export declare class ServiceRebuilder extends ServiceModuleBase implements Rebuilder { + private appLifecycle; + private API; + private UI; + private setting; + private remote; + private databaseEvents; + private storageAccess; + private replicator; + private vault; + private replication; + private database; + private fileHandler; + private control; + constructor(services: ServiceRebuilderDependencies); + $performRebuildDB(method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks"): Promise; + informOptionalFeatures(): Promise; + askUsingOptionalFeature(opt: { + enableFetch?: boolean; + enableOverwrite?: boolean; + }): Promise; + rebuildRemote(): Promise; + $rebuildRemote(): Promise; + rebuildEverything(): Promise; + $rebuildEverything(): Promise; + $fetchLocal(makeLocalChunkBeforeSync?: boolean, preventMakeLocalFilesBeforeSync?: boolean): Promise; + $fetchLocalDBFast(autoResume: boolean): Promise; + scheduleRebuild(): Promise; + scheduleFetch(): Promise; + private _tryResetRemoteDatabase; + private _onResetLocalDatabase; + suspendAllSync(): Promise; + suspendReflectingDatabase(ignoreMinIO?: boolean): Promise; + resumeReflectingDatabase(ignoreMinIO?: boolean): Promise; + fetchLocal(makeLocalChunkBeforeSync?: boolean, preventMakeLocalFilesBeforeSync?: boolean, autoResume?: boolean): Promise; + fetchLocalDBFast(autoResume: boolean): Promise; + /** + * Finish rebuild process with resuming the reflection. + * + * @param ignoreMinIO Whether to ignore minio for resuming the reflection. + */ + finishRebuild(ignoreMinIO?: boolean): Promise; + /** + * Fetch local database with making all chunks. + * This is a wrapper for {@link fetchLocal} with makeLocalChunkBeforeSync = true. + * + * @returns + */ + fetchLocalWithRebuild(): Promise; + private _allSuspendAllSync; + resetLocalDatabase(): Promise; +} diff --git a/_types/lib/src/serviceModules/ServiceDatabaseFileAccessBase.d.ts b/_types/lib/src/serviceModules/ServiceDatabaseFileAccessBase.d.ts new file mode 100644 index 0000000..eaf3d45 --- /dev/null +++ b/_types/lib/src/serviceModules/ServiceDatabaseFileAccessBase.d.ts @@ -0,0 +1,38 @@ +import type { UXFileInfoStub, UXFileInfo } from "@lib/common/models/fileaccess.type"; +import type { FilePathWithPrefix, MetaEntry, LoadedEntry, FilePath } from "@lib/common/models/db.type"; +import type { DatabaseFileAccess } from "@lib/interfaces/DatabaseFileAccess"; +import type { StorageAccess } from "@lib/interfaces/StorageAccess"; +import type { APIService } from "@lib/services/base/APIService"; +import type { DatabaseService } from "@lib/services/base/DatabaseService"; +import type { PathService } from "@lib/services/base/PathService"; +import type { VaultService } from "@lib/services/base/VaultService"; +import { ServiceModuleBase } from "./ServiceModuleBase"; +export interface ServiceDatabaseFileAccessDependencies { + API: APIService; + vault: VaultService; + storageAccess: StorageAccess; + path: PathService; + database: DatabaseService; +} +export declare class ServiceDatabaseFileAccessBase extends ServiceModuleBase implements DatabaseFileAccess { + private vault; + private storageAccess; + private path; + private database; + constructor(services: ServiceDatabaseFileAccessDependencies); + checkIsTargetFile(file: UXFileInfoStub | FilePathWithPrefix): Promise; + delete(file: UXFileInfoStub | FilePathWithPrefix, rev?: string): Promise; + createChunks(file: UXFileInfo, force?: boolean, skipCheck?: boolean): Promise; + store(file: UXFileInfo, force?: boolean, skipCheck?: boolean): Promise; + storeAsConflictedRevision(file: UXFileInfo, currentRev: string, skipCheck?: boolean): Promise; + storeContent(path: FilePathWithPrefix, content: string): Promise; + private __store; + private getParentRev; + hasContentInRevisionHistory(file: UXFileInfoStub | FilePathWithPrefix, content: string | string[] | Blob | ArrayBuffer, currentRev?: string): Promise; + getConflictedRevs(file: UXFileInfoStub | FilePathWithPrefix): Promise; + fetch(file: UXFileInfoStub | FilePathWithPrefix, rev?: string, waitForReady?: boolean, skipCheck?: boolean): Promise; + fetchEntryMeta(file: UXFileInfoStub | FilePathWithPrefix, rev?: string, skipCheck?: boolean): Promise; + fetchEntryFromMeta(meta: MetaEntry, waitForReady?: boolean, skipCheck?: boolean): Promise; + fetchEntry(file: UXFileInfoStub | FilePathWithPrefix, rev?: string, waitForReady?: boolean, skipCheck?: boolean): Promise; + deleteFromDBbyPath(fullPath: FilePath | FilePathWithPrefix, rev?: string): Promise; +} diff --git a/_types/lib/src/serviceModules/ServiceFileAccessBase.d.ts b/_types/lib/src/serviceModules/ServiceFileAccessBase.d.ts new file mode 100644 index 0000000..26046ca --- /dev/null +++ b/_types/lib/src/serviceModules/ServiceFileAccessBase.d.ts @@ -0,0 +1,65 @@ +import type { FilePath, FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { UXDataWriteOptions, UXFileInfo, UXFileInfoStub, UXFolderInfo, UXStat } from "@lib/common/models/fileaccess.type"; +import { ServiceModuleBase } from "./ServiceModuleBase"; +import type { APIService } from "@lib/services/base/APIService"; +import type { IStorageAccessManager, StorageAccess } from "@lib/interfaces/StorageAccess.ts"; +import type { AppLifecycleService } from "@lib/services/base/AppLifecycleService"; +import type { FileProcessingService } from "@lib/services/base/FileProcessingService"; +import { StorageEventManager } from "@lib/interfaces/StorageEventManager.ts"; +import type { CustomRegExp } from "@lib/common/utils.regexp"; +import type { VaultService } from "@lib/services/base/VaultService"; +import type { SettingService } from "@lib/services/base/SettingService"; +import type { FileAccessBase, ExtractFile, ExtractFolder } from "./FileAccessBase"; +import type { IFileSystemAdapter } from "./adapters"; +export interface StorageAccessBaseDependencies> { + API: APIService; + appLifecycle: AppLifecycleService; + fileProcessing: FileProcessingService; + vault: VaultService; + setting: SettingService; + storageEventManager: StorageEventManager; + storageAccessManager: IStorageAccessManager; + vaultAccess: FileAccessBase; +} +export declare class ServiceFileAccessBase>// eslint-disable-line @typescript-eslint/no-explicit-any + extends ServiceModuleBase> implements StorageAccess { + private vaultAccess; + private vaultManager; + private vault; + private setting; + constructor(services: StorageAccessBaseDependencies); + restoreState(): Promise; + _everyOnFirstInitialize(): Promise; + _everyCommitPendingFileEvent(): Promise; + normalisePath(path: string): string; + writeFileAuto(path: string, data: string | ArrayBuffer, opt?: UXDataWriteOptions): Promise; + readFileAuto(path: string): Promise; + readFileText(path: string): Promise; + isExists(path: string): Promise; + writeHiddenFileAuto(path: string, data: string | ArrayBuffer, opt?: UXDataWriteOptions): Promise; + appendHiddenFile(path: string, data: string, opt?: UXDataWriteOptions): Promise; + stat(path: string): Promise; + statHidden(path: string): Promise; + removeHidden(path: string): Promise; + readHiddenFileAuto(path: string): Promise; + readHiddenFileText(path: string): Promise; + readHiddenFileBinary(path: string): Promise; + isExistsIncludeHidden(path: string): Promise; + ensureDir(path: string): Promise; + _triggerFileEvent(event: string, path: string): Promise; + triggerFileEvent(event: string, path: string): void; + triggerHiddenFile(path: string): Promise; + getFileStub(path: string): Promise; + readStubContent(stub: UXFileInfoStub): Promise; + getStub(path: string): Promise; + getFiles(): Promise; + getFileNames(): Promise; + getFilesIncludeHidden(basePath: string, includeFilter?: CustomRegExp[], excludeFilter?: CustomRegExp[], skipFolder?: string[]): Promise; + touched(file: UXFileInfoStub | FilePathWithPrefix): Promise; + recentlyTouched(file: UXFileInfoStub | FilePathWithPrefix): Promise; + clearTouched(): void; + delete(file: FilePathWithPrefix | UXFileInfoStub | string, force: boolean): Promise; + trash(file: FilePathWithPrefix | UXFileInfoStub | string, system: boolean): Promise; + __deleteVaultItem(file: ExtractFile | ExtractFolder): Promise; + deleteVaultItem(fileSrc: FilePathWithPrefix | UXFileInfoStub | UXFolderInfo): Promise; +} diff --git a/_types/lib/src/serviceModules/ServiceFileHandlerBase.d.ts b/_types/lib/src/serviceModules/ServiceFileHandlerBase.d.ts new file mode 100644 index 0000000..315715d --- /dev/null +++ b/_types/lib/src/serviceModules/ServiceFileHandlerBase.d.ts @@ -0,0 +1,49 @@ +import type { AnyEntry, FilePath, FilePathWithPrefix, MetaEntry } from "@lib/common/models/db.type"; +import type { UXFileInfo, UXFileInfoStub, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { IFileHandler } from "@lib/interfaces/FileHandler.ts"; +import { ServiceModuleBase } from "./ServiceModuleBase"; +import type { APIService } from "@lib/services/base/APIService.ts"; +import type { DatabaseFileAccess } from "@lib/interfaces/DatabaseFileAccess.ts"; +import type { StorageAccess } from "@lib/interfaces/StorageAccess.ts"; +import type { FileProcessingService } from "@lib/services/base/FileProcessingService.ts"; +import type { ReplicationService } from "@lib/services/base/ReplicationService.ts"; +import type { ConflictService } from "@lib/services/base/ConflictService.ts"; +import type { PathService } from "@lib/services/base/PathService.ts"; +import type { SettingService } from "@lib/services/base/SettingService.ts"; +import type { VaultService } from "@lib/services/base/VaultService.ts"; +export interface ServiceFileHandlerDependencies { + API: APIService; + databaseFileAccess: DatabaseFileAccess; + storageAccess: StorageAccess; + fileProcessing: FileProcessingService; + replication: ReplicationService; + conflict: ConflictService; + path: PathService; + setting: SettingService; + vault: VaultService; +} +export declare abstract class ServiceFileHandlerBase extends ServiceModuleBase implements IFileHandler { + private databaseFileAccess; + private storageAccess; + private conflict; + private path; + private setting; + private vault; + constructor(services: ServiceFileHandlerDependencies); + get db(): DatabaseFileAccess; + get storage(): StorageAccess; + getPath(entry: AnyEntry): FilePathWithPrefix; + getPathWithoutPrefix(entry: AnyEntry): FilePathWithPrefix; + readFileFromStub(file: UXFileInfoStub | UXFileInfo): Promise; + private infoToStub; + storeFileToDB(info: UXFileInfoStub | UXFileInfo | UXInternalFileInfoStub | FilePathWithPrefix, force?: boolean, onlyChunks?: boolean): Promise; + deleteFileFromDB(info: UXFileInfoStub | UXInternalFileInfoStub | FilePath): Promise; + deleteRevisionFromDB(info: UXFileInfoStub | FilePath | FilePathWithPrefix, rev: string): Promise; + resolveConflictedByDeletingRevision(info: UXFileInfoStub | FilePath, rev: string): Promise; + dbToStorageWithSpecificRev(info: UXFileInfoStub | UXFileInfo | FilePath | null, rev: string, force?: boolean): Promise; + dbToStorage(entryInfo: MetaEntry | FilePathWithPrefix, info: UXFileInfoStub | UXFileInfo | FilePath | null, force?: boolean): Promise; + private preserveUnsyncedStorageAsConflict; + private _anyHandlerProcessesFileEvent; + _anyProcessReplicatedDoc(entry: MetaEntry): Promise; + createAllChunks(showingNotice?: boolean): Promise; +} diff --git a/_types/lib/src/serviceModules/ServiceModuleBase.d.ts b/_types/lib/src/serviceModules/ServiceModuleBase.d.ts new file mode 100644 index 0000000..09d1f78 --- /dev/null +++ b/_types/lib/src/serviceModules/ServiceModuleBase.d.ts @@ -0,0 +1,10 @@ +import type { APIService } from "@lib/services/base/APIService"; +import { createInstanceLogFunction } from "@lib/services/lib/logUtils"; +export interface ServiceModuleBaseDependencies { + API: APIService; +} +export declare abstract class ServiceModuleBase { + _log: ReturnType; + get name(): string; + constructor(services: T); +} diff --git a/_types/lib/src/serviceModules/adapters/IConversionAdapter.d.ts b/_types/lib/src/serviceModules/adapters/IConversionAdapter.d.ts new file mode 100644 index 0000000..16a037f --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/IConversionAdapter.d.ts @@ -0,0 +1,15 @@ +import type { UXFileInfoStub, UXFolderInfo } from "@lib/common/models/fileaccess.type"; +/** + * Conversion adapter interface + * Converts between native file system types and universal types + */ +export interface IConversionAdapter { + /** + * Convert a native file object to a universal file info stub + */ + nativeFileToUXFileInfoStub(file: TNativeFile): UXFileInfoStub; + /** + * Convert a native folder object to a universal folder info + */ + nativeFolderToUXFolder(folder: TNativeFolder): UXFolderInfo; +} diff --git a/_types/lib/src/serviceModules/adapters/IFileSystemAdapter.d.ts b/_types/lib/src/serviceModules/adapters/IFileSystemAdapter.d.ts new file mode 100644 index 0000000..b0888f9 --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/IFileSystemAdapter.d.ts @@ -0,0 +1,47 @@ +import type { FilePath } from "@lib/common/models/db.type"; +import type { UXStat } from "@lib/common/models/fileaccess.type"; +import type { IPathAdapter } from "./IPathAdapter.ts"; +import type { ITypeGuardAdapter } from "./ITypeGuardAdapter.ts"; +import type { IConversionAdapter } from "./IConversionAdapter.ts"; +import type { IStorageAdapter } from "./IStorageAdapter.ts"; +import type { IVaultAdapter } from "./IVaultAdapter.ts"; +/** + * Main file system adapter interface + * Composes all other adapters and provides platform-specific operations + */ +export interface IFileSystemAdapter { + /** Path operations */ + readonly path: IPathAdapter; + /** Type guard operations */ + readonly typeGuard: ITypeGuardAdapter; + /** Conversion operations */ + readonly conversion: IConversionAdapter; + /** Storage operations */ + readonly storage: IStorageAdapter; + /** Vault operations */ + readonly vault: IVaultAdapter; + /** + * Get a file or folder by path (case-sensitive) + */ + getAbstractFileByPath(path: FilePath | string): Promise; + /** + * Get a file or folder by path (case-insensitive) + */ + getAbstractFileByPathInsensitive(path: FilePath | string): Promise; + /** + * Get all files in the vault + */ + getFiles(): Promise; + /** + * Get file statistics from a native file object + */ + statFromNative(file: TNativeFile): Promise; + /** + * Reconcile internal file state + * Platform-specific operation for syncing internal metadata + */ + reconcileInternalFile(path: string): Promise; +} diff --git a/_types/lib/src/serviceModules/adapters/IPathAdapter.d.ts b/_types/lib/src/serviceModules/adapters/IPathAdapter.d.ts new file mode 100644 index 0000000..87571ec --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/IPathAdapter.d.ts @@ -0,0 +1,15 @@ +import type { FilePath } from "@lib/common/models/db.type"; +/** + * Path operations adapter interface + * Handles path normalization and extraction + */ +export interface IPathAdapter { + /** + * Get the path from a file object or return the path string as-is + */ + getPath(file: TNativeAbstractFile | string): FilePath; + /** + * Normalize a path according to the platform's conventions + */ + normalisePath(path: string): string; +} diff --git a/_types/lib/src/serviceModules/adapters/IStorageAdapter.d.ts b/_types/lib/src/serviceModules/adapters/IStorageAdapter.d.ts new file mode 100644 index 0000000..5c59917 --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/IStorageAdapter.d.ts @@ -0,0 +1,54 @@ +import type { UXDataWriteOptions, UXStat } from "@lib/common/models/fileaccess.type"; +/** + * Storage adapter interface + * Low-level file system operations (adapter level) + */ +export interface IStorageAdapter { + /** + * Check if a file or directory exists + */ + exists(path: string): Promise; + /** + * Get file statistics, returns null if file doesn't exist + */ + trystat(path: string): Promise; + /** + * Get file statistics + */ + stat(path: string): Promise; + /** + * Create a directory + */ + mkdir(path: string): Promise; + /** + * Remove a file or directory + */ + remove(path: string): Promise; + /** + * Read a file as text + */ + read(path: string): Promise; + /** + * Read a file as binary + */ + readBinary(path: string): Promise; + /** + * Write text to a file + */ + write(path: string, data: string, options?: UXDataWriteOptions): Promise; + /** + * Write binary data to a file + */ + writeBinary(path: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise; + /** + * Append text to a file + */ + append(path: string, data: string, options?: UXDataWriteOptions): Promise; + /** + * List files and folders in a directory + */ + list(basePath: string): Promise<{ + files: string[]; + folders: string[]; + }>; +} diff --git a/_types/lib/src/serviceModules/adapters/ITypeGuardAdapter.d.ts b/_types/lib/src/serviceModules/adapters/ITypeGuardAdapter.d.ts new file mode 100644 index 0000000..fb567df --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/ITypeGuardAdapter.d.ts @@ -0,0 +1,14 @@ +/** + * Type guard adapter interface + * Provides runtime type checking for native file system objects + */ +export interface ITypeGuardAdapter { + /** + * Check if the given object is a file + */ + isFile(file: unknown): file is TNativeFile; + /** + * Check if the given object is a folder + */ + isFolder(item: unknown): item is TNativeFolder; +} diff --git a/_types/lib/src/serviceModules/adapters/IVaultAdapter.d.ts b/_types/lib/src/serviceModules/adapters/IVaultAdapter.d.ts new file mode 100644 index 0000000..6683259 --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/IVaultAdapter.d.ts @@ -0,0 +1,47 @@ +import type { UXDataWriteOptions } from "@lib/common/models/fileaccess.type"; +/** + * Vault adapter interface + * High-level file operations that interact with the vault layer + */ +export interface IVaultAdapter { + /** + * Read a file as text + */ + read(file: TNativeFile): Promise; + /** + * Read a file using cached content if available + */ + cachedRead(file: TNativeFile): Promise; + /** + * Read a file as binary + */ + readBinary(file: TNativeFile): Promise; + /** + * Modify an existing file with text content + */ + modify(file: TNativeFile, data: string, options?: UXDataWriteOptions): Promise; + /** + * Modify an existing file with binary content + */ + modifyBinary(file: TNativeFile, data: ArrayBuffer, options?: UXDataWriteOptions): Promise; + /** + * Create a new file with text content + */ + create(path: string, data: string, options?: UXDataWriteOptions): Promise; + /** + * Create a new file with binary content + */ + createBinary(path: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise; + /** + * Delete a file or folder + */ + delete(file: unknown, force?: boolean): Promise; + /** + * Move a file or folder to trash + */ + trash(file: unknown, force?: boolean): Promise; + /** + * Trigger an event in the vault + */ + trigger(name: string, ...data: any[]): any; +} diff --git a/_types/lib/src/serviceModules/adapters/index.d.ts b/_types/lib/src/serviceModules/adapters/index.d.ts new file mode 100644 index 0000000..7d09285 --- /dev/null +++ b/_types/lib/src/serviceModules/adapters/index.d.ts @@ -0,0 +1,6 @@ +export type { IPathAdapter } from "./IPathAdapter.ts"; +export type { ITypeGuardAdapter } from "./ITypeGuardAdapter.ts"; +export type { IConversionAdapter } from "./IConversionAdapter.ts"; +export type { IStorageAdapter } from "./IStorageAdapter.ts"; +export type { IVaultAdapter } from "./IVaultAdapter.ts"; +export type { IFileSystemAdapter } from "./IFileSystemAdapter.ts"; diff --git a/_types/lib/src/services/BrowserServices.d.ts b/_types/lib/src/services/BrowserServices.d.ts new file mode 100644 index 0000000..bc1282a --- /dev/null +++ b/_types/lib/src/services/BrowserServices.d.ts @@ -0,0 +1,7 @@ +import { InjectableVaultServiceCompat } from "./implements/injectable/InjectableVaultService"; +import { ServiceContext } from "./base/ServiceBase"; +import { InjectableServiceHub } from "./implements/injectable/InjectableServiceHub"; +export declare class BrowserServiceHub extends InjectableServiceHub { + get vault(): InjectableVaultServiceCompat; + constructor(); +} diff --git a/_types/lib/src/services/HeadlessServices.d.ts b/_types/lib/src/services/HeadlessServices.d.ts new file mode 100644 index 0000000..099dab7 --- /dev/null +++ b/_types/lib/src/services/HeadlessServices.d.ts @@ -0,0 +1,10 @@ +import { ServiceContext } from "./base/ServiceBase"; +import { InjectableServiceHub } from "./implements/injectable/InjectableServiceHub"; +import type { DatabaseService } from "./base/DatabaseService.ts"; +type Constructor = new (...args: any[]) => T; +export declare class HeadlessServiceHub extends InjectableServiceHub { + constructor(_context?: T, overrideServiceConstructor?: { + database?: Constructor>; + }); +} +export {}; diff --git a/_types/lib/src/services/InjectableServices.d.ts b/_types/lib/src/services/InjectableServices.d.ts new file mode 100644 index 0000000..1fc636b --- /dev/null +++ b/_types/lib/src/services/InjectableServices.d.ts @@ -0,0 +1 @@ +export { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub.ts"; diff --git a/_types/lib/src/services/ServiceHub.d.ts b/_types/lib/src/services/ServiceHub.d.ts new file mode 100644 index 0000000..d58f8d4 --- /dev/null +++ b/_types/lib/src/services/ServiceHub.d.ts @@ -0,0 +1,81 @@ +import type { UIService } from "./implements/base/UIService.ts"; +import type { ConfigService } from "./base/ConfigService.ts"; +import type { TestService } from "./base/TestService.ts"; +import type { VaultService } from "./base/VaultService.ts"; +import type { TweakValueService } from "./base/TweakValueService.ts"; +import type { SettingService } from "./base/SettingService.ts"; +import type { AppLifecycleService } from "./base/AppLifecycleService.ts"; +import type { ConflictService } from "./base/ConflictService.ts"; +import type { RemoteService } from "./base/RemoteService.ts"; +import type { ReplicationService } from "./base/ReplicationService.ts"; +import type { ReplicatorService } from "./base/ReplicatorService.ts"; +import type { FileProcessingService } from "./base/FileProcessingService.ts"; +import type { DatabaseEventService } from "./base/DatabaseEventService.ts"; +import type { DatabaseService } from "./base/DatabaseService.ts"; +import type { PathService } from "./base/PathService.ts"; +import type { APIService } from "./base/APIService.ts"; +import type { ServiceContext } from "./base/ServiceBase.ts"; +import type { IServiceHub } from "./base/IService.ts"; +import type { KeyValueDBService } from "./base/KeyValueDBService.ts"; +import type { ControlService } from "./base/ControlService.ts"; +export type ServiceInstances = { + API?: APIService; + path?: PathService; + database?: DatabaseService; + databaseEvents?: DatabaseEventService; + replicator?: ReplicatorService; + fileProcessing?: FileProcessingService; + replication?: ReplicationService; + remote?: RemoteService; + conflict?: ConflictService; + appLifecycle?: AppLifecycleService; + setting?: SettingService; + tweakValue?: TweakValueService; + vault?: VaultService; + test?: TestService; + ui?: UIService; + config?: ConfigService; + keyValueDB?: KeyValueDBService; + control?: ControlService; +}; +export declare abstract class ServiceHub implements IServiceHub { + protected context: T; + protected abstract _api: APIService; + protected abstract _path: PathService; + protected abstract _database: DatabaseService; + protected abstract _databaseEvents: DatabaseEventService; + protected abstract _replicator: ReplicatorService; + protected abstract _fileProcessing: FileProcessingService; + protected abstract _replication: ReplicationService; + protected abstract _remote: RemoteService; + protected abstract _conflict: ConflictService; + protected abstract _appLifecycle: AppLifecycleService; + protected abstract _setting: SettingService; + protected abstract _tweakValue: TweakValueService; + protected abstract _vault: VaultService; + protected abstract _test: TestService; + protected abstract _ui: UIService; + protected abstract _config: ConfigService; + protected abstract _keyValueDB: KeyValueDBService; + protected abstract _control: ControlService; + protected _injected: ServiceInstances; + constructor(context: T, services?: ServiceInstances); + get API(): APIService; + get path(): PathService; + get database(): DatabaseService; + get databaseEvents(): DatabaseEventService; + get replicator(): ReplicatorService; + get fileProcessing(): FileProcessingService; + get replication(): ReplicationService; + get remote(): RemoteService; + get conflict(): ConflictService; + get appLifecycle(): AppLifecycleService; + get setting(): SettingService; + get tweakValue(): TweakValueService; + get vault(): VaultService; + get test(): TestService; + get UI(): UIService; + get config(): ConfigService; + get keyValueDB(): KeyValueDBService; + get control(): ControlService; +} diff --git a/_types/lib/src/services/base/APIService.d.ts b/_types/lib/src/services/base/APIService.d.ts new file mode 100644 index 0000000..d81c28d --- /dev/null +++ b/_types/lib/src/services/base/APIService.d.ts @@ -0,0 +1,93 @@ +import type { FetchHttpHandler } from "@smithy/fetch-http-handler"; +import type { LOG_LEVEL } from "@lib/common/logger"; +import type { IAPIService, ICommandCompat } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import type { Confirm } from "@lib/interfaces/Confirm"; +/** + * The APIService provides methods for interacting with the plug-in's API, + */ +export declare abstract class APIService extends ServiceBase implements IAPIService { + /** + * Get a custom fetch handler for making HTTP requests (e.g., S3 without CORS issues). + */ + abstract getCustomFetchHandler(): FetchHttpHandler; + /** + * Add a log entry to the log (Now not used). + * @param message The log message. + * @param level The log level. + * @param key The log key. + */ + abstract addLog(message: unknown, level: LOG_LEVEL, key: string): void; + /** + * Check if the app is running on a mobile device. + * @returns true if running on mobile, false otherwise. + */ + abstract isMobile(): boolean; + /** + * Show a window (or in Obsidian, a leaf). + * @param type The type of window to show. + */ + abstract showWindow(type: string): Promise; + /** + * Show a window on the right sidebar when supported. + * Platforms that do not support sidebars can fall back to showWindow. + */ + showWindowOnRight(type: string): Promise; + /** + * returns App ID. In Obsidian, it is vault ID. + */ + abstract getAppID(): string; + /** + * Returns the vaultName which system has identified, without any additional suffix. + */ + abstract getSystemVaultName(): string; + /** + * Check if the last POST request failed due to payload size. + */ + abstract getPlatform(): string; + abstract getAppVersion(): string; + abstract getPluginVersion(): string; + abstract getCrypto(): Crypto; + /** + * Register a command to the runtime. + * @param command + */ + abstract addCommand(command: TCommand): TCommand; + /** + * Register a window (or leaf) type to the runtime. + * @param type + * @param factory + */ + abstract registerWindow(type: string, factory: (leaf: any) => any): void; + /** + * Add a ribbon icon to the UI. + * @param icon + * @param title + * @param callback + */ + abstract addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement; + /** + * Register a protocol handler. + * @param action The action string for the protocol. + * @param handler The handler function for the protocol. + */ + abstract registerProtocolHandler(action: string, handler: (params: Record) => any): void; + /** + * Get the basic UI component for showing a confirmation dialog to the user. + */ + abstract get confirm(): Confirm; + requestCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + responseCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + get isOnline(): boolean; + webCompatFetch(req: string | Request, opts?: RequestInit): Promise; + nativeFetch(req: string | Request, opts?: RequestInit): Promise; + abstract addStatusBarItem(): HTMLElement | undefined; + setInterval(handler: () => void, timeout: number): number; + clearInterval(timerId: number): void; + /** + * Get the system configuration directory. + * This is used for storing configuration files in a consistent location across platforms. + * @returns + */ + getSystemConfigDir(): string; +} diff --git a/_types/lib/src/services/base/AppLifecycleService.d.ts b/_types/lib/src/services/base/AppLifecycleService.d.ts new file mode 100644 index 0000000..65be0d5 --- /dev/null +++ b/_types/lib/src/services/base/AppLifecycleService.d.ts @@ -0,0 +1,132 @@ +import type { IAppLifecycleService, ISettingService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +export interface AppLifecycleServiceDependencies { + settingService: ISettingService; +} +/** + * The AppLifecycleService provides methods for managing the plug-in's lifecycle events. + */ +export declare abstract class AppLifecycleService extends ServiceBase implements IAppLifecycleService { + protected readonly settingService: ISettingService; + constructor(context: T, dependencies: AppLifecycleServiceDependencies); + /** + * Event triggered when the plug-in's layout is ready. + * In Obsidian, it is after the workspace is ready. + */ + readonly onLayoutReady: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in is being initialized for the first time. + * This is only called once per plug-in lifecycle. + */ + readonly onFirstInitialise: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in is fully ready. + * This is called after all initialisation processes are complete. + */ + readonly onReady: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered to wire up necessary event listeners. + * This is typically called during the initialisation phase. + */ + readonly onWireUpEvents: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in is being initialised. + */ + readonly onInitialise: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in is loading. + * This is typically called during the quite early initialisation phase, before everything. + * In Obsidian, it is in the onload() method of the plugin. + */ + readonly onLoad: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in's settings have been loaded and applied. + */ + readonly onSettingLoaded: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in has fully loaded. + * This is typically called after all initialisation and loading processes are complete. + */ + readonly onLoaded: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Scan for any startup issues that may affect the plug-in's operation. + */ + readonly onScanningStartupIssues: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in is unloading (e.g., during app shutdown or plug-in disable). + * This is typically called during the unload() method of the plugin. + * Entry point to unload everything. + */ + readonly onAppUnload: import("@lib/services/lib/HandlerUtils").CollectiveHandlerFunction<() => Promise, any>; + /** + * Event triggered before the plug-in is unloaded. + * This is typically used to perform any necessary cleanup or save state before the plug-in is unloaded. + */ + readonly onBeforeUnload: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the plug-in is being unloaded. + */ + readonly onUnload: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Perform an immediate restart of the application. + * Note that this is not graceful, and not only the plug-in. APPLICATION (means Obsidian) will be restarted. + */ + abstract performRestart(): void; + /** + * Ask the user for a restart. + * @param message Optional message to display to the user when asking for a restart. + */ + abstract askRestart(message?: string): void; + /** + * Schedule a restart of the application. + * After the current operation is done, the application will be restarted. + * Note that this is not graceful, and not only the plug-in. APPLICATION (means Obsidian) will be restarted. + */ + abstract scheduleRestart(): void; + /** + * Event triggered when the application is being suspended (e.g., system sleep). + */ + readonly onSuspending: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered when the application is resuming from a suspended state. + */ + readonly onResuming: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered after the application has resumed from a suspended state. + */ + readonly onResumed: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + private _isSuspended; + /** + * Check if the plug-in is currently suspended. + * Also consider the plug-in as suspended if it is not configured, to prevent any issues before configuration. + */ + isSuspended(): boolean; + /** + * Set the suspension state of the plug-in. + * @param suspend Set to true to suspend the plug-in, false to resume. + */ + setSuspended(suspend: boolean): void; + private _isReady; + /** + * Check if the plug-in is ready. + * A ready plug-in means it has been fully initialised and is operational. + * If not ready, most operations will be blocked. + */ + isReady(): boolean; + /** + * Mark the plug-in as ready. + */ + markIsReady(): void; + /** + * Reset the ready state of the plug-in. + */ + resetIsReady(): void; + /** + * Check if a restart has been scheduled. + */ + abstract isReloadingScheduled(): boolean; + /** + * Get unresolved error messages. + */ + readonly getUnresolvedMessages: import("@lib/services/lib/HandlerUtils").CollectiveHandlerFunction<() => Promise<(string | Error)[][]>, any>; +} diff --git a/_types/lib/src/services/base/ConfigService.d.ts b/_types/lib/src/services/base/ConfigService.d.ts new file mode 100644 index 0000000..25f3b28 --- /dev/null +++ b/_types/lib/src/services/base/ConfigService.d.ts @@ -0,0 +1,7 @@ +import type { IConfigService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +export declare abstract class ConfigService extends ServiceBase implements IConfigService { + abstract getSmallConfig(key: string): string | null; + abstract setSmallConfig(key: string, value: string): void; + abstract deleteSmallConfig(key: string): void; +} diff --git a/_types/lib/src/services/base/ConflictService.d.ts b/_types/lib/src/services/base/ConflictService.d.ts new file mode 100644 index 0000000..7216fc4 --- /dev/null +++ b/_types/lib/src/services/base/ConflictService.d.ts @@ -0,0 +1,55 @@ +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { MISSING_OR_ERROR, AUTO_MERGED } from "@lib/common/models/shared.const.symbols"; +import type { IConflictService } from "./IService"; +import { ServiceBase } from "./ServiceBase"; +import type { ServiceContext } from "./ServiceBase"; +/** + * The ConflictService provides methods for handling file conflicts. + */ +export declare abstract class ConflictService extends ServiceBase implements IConflictService { + /** + * Get an optional conflict check method for a given file (virtual) path. + */ + readonly getOptionalConflictCheckMethod: import("@lib/services/lib/HandlerUtils").MultipleHandlerFunction<(path: FilePathWithPrefix) => Promise, any>; + /** + * Queue a check for conflicts if the file is currently open in the editor. + * @param path The file (virtual) path to check for conflicts. + */ + abstract queueCheckForIfOpen(path: FilePathWithPrefix): Promise; + /** + * Queue a check for conflicts for a given file (virtual) path. + * @param path The file (virtual) path to check for conflicts. + */ + abstract queueCheckFor(path: FilePathWithPrefix): Promise; + /** + * Ensure all queued file conflict checks are processed. + */ + abstract ensureAllProcessed(): Promise; + /** + * Resolve a conflict by user interaction (e.g., showing a modal dialog). + * @param filename The file (virtual) path with conflict. + * @param conflictCheckResult The result of the conflict check. + * @returns A promise that resolves to true if the conflict was resolved, false if not, or undefined if no action was taken. + */ + readonly resolveByUserInteraction: import("@lib/services/lib/HandlerUtils").MultipleHandlerFunction<(filename: FilePathWithPrefix, conflictCheckResult: import("../../common/types").diff_result) => Promise, any>; + /** + * Resolve a conflict by deleting a specific revision. + * @param path The file (virtual) path with conflict. + * @param deleteRevision The revision to delete. + * @param title The title of the conflict (for user display). + */ + abstract resolveByDeletingRevision(path: FilePathWithPrefix, deleteRevision: string, title: string): Promise; + /** + * Resolve a conflict as several possible strategies. + * It may involve user interaction (means raising resolveByUserInteraction). + * @param filename The file (virtual) path to resolve. + */ + abstract resolve(filename: FilePathWithPrefix): Promise; + /** + * Resolve a conflict by choosing the newest version. + * @param filename The file (virtual) path to resolve. + */ + abstract resolveByNewest(filename: FilePathWithPrefix): Promise; + abstract resolveAllConflictedFilesByNewerOnes(): Promise; + conflictProcessQueueCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +} diff --git a/_types/lib/src/services/base/ControlService.d.ts b/_types/lib/src/services/base/ControlService.d.ts new file mode 100644 index 0000000..0f67af9 --- /dev/null +++ b/_types/lib/src/services/base/ControlService.d.ts @@ -0,0 +1,54 @@ +import { createInstanceLogFunction } from "@lib/services/lib/logUtils"; +import type { APIService } from "./APIService"; +import type { DatabaseService } from "./DatabaseService"; +import type { IControlService, IFileProcessingService, IReplicatorService, ISettingService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import { type PromiseWithResolvers } from "octagonal-wheels/promises"; +import type { AppLifecycleService } from "./AppLifecycleService"; +export interface ControlServiceDependencies { + appLifecycleService: AppLifecycleService; + replicatorService: IReplicatorService; + settingService: ISettingService; + databaseService: DatabaseService; + fileProcessingService: IFileProcessingService; + APIService: APIService; +} +/** + * The ControlService provides methods for controlling the overall behaviour of the plugin, such as applying settings or handling lifecycle events. + */ +export declare class ControlService extends ServiceBase implements IControlService { + protected services: ControlServiceDependencies; + protected _log: ReturnType; + protected _unloaded: boolean; + protected _activated: PromiseWithResolvers; + /** + * Check if the plug-in has been unloaded. + */ + hasUnloaded(): boolean; + constructor(context: T, dependencies: ControlServiceDependencies); + get activated(): Promise; + private onActivated; + /** + * Apply current settings to reflect the changes immediately. + * @returns + */ + applySettings(): Promise; + private _onLiveSyncUnload; + /** + * Called when the plugin is loaded. It will trigger the app lifecycle event onLoad. + * Main process should be called in onReady. + * @returns + */ + onLoad(): Promise; + /** + * Main entry point of the plugin. It will trigger the app lifecycle event onReady. + * Usually it should be called on `app.workspace.onLayoutReady` + * @returns + */ + onReady(): Promise; + /** + * On unload event of the plugin. It will trigger the app lifecycle event onUnload. + * @returns + */ + onUnload(): Promise; +} diff --git a/_types/lib/src/services/base/DatabaseEventService.d.ts b/_types/lib/src/services/base/DatabaseEventService.d.ts new file mode 100644 index 0000000..2b59369 --- /dev/null +++ b/_types/lib/src/services/base/DatabaseEventService.d.ts @@ -0,0 +1,38 @@ +import type { IDatabaseEventService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +/** + * The DatabaseEventService provides methods for handling database lifecycle events. + */ +export declare abstract class DatabaseEventService extends ServiceBase implements IDatabaseEventService { + /** + * Event triggered when the database is about to be unloaded. + */ + readonly onUnloadDatabase: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(db: import("../../pouchdb/LiveSyncLocalDB").LiveSyncLocalDB) => Promise>; + /** + * Event triggered when the database is about to be closed. + */ + readonly onCloseDatabase: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(db: import("../../pouchdb/LiveSyncLocalDB").LiveSyncLocalDB) => Promise>; + /** + * Event triggered when the database is being initialized. + */ + readonly onDatabaseInitialisation: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(db: import("../../pouchdb/LiveSyncLocalDB").LiveSyncLocalDB) => Promise>; + /** + * Event triggered when the database has been initialized. + */ + readonly onDatabaseInitialised: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(showNotice: boolean) => Promise>; + /** + * Event triggered when the database is being reset. + */ + readonly onResetDatabase: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(db: import("../../pouchdb/LiveSyncLocalDB").LiveSyncLocalDB) => Promise>; + /** + * Event triggered when the database is ready for use. + */ + readonly onDatabaseHasReady: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Initialize the database. + * @param showingNotice Whether to show a notice to the user. + * @param reopenDatabase Whether to reopen the database if it is already open. + * @param ignoreSuspending Whether to ignore any suspending state. + */ + readonly initialiseDatabase: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(showingNotice?: boolean, reopenDatabase?: boolean, ignoreSuspending?: boolean) => Promise>; +} diff --git a/_types/lib/src/services/base/DatabaseService.d.ts b/_types/lib/src/services/base/DatabaseService.d.ts new file mode 100644 index 0000000..de2d358 --- /dev/null +++ b/_types/lib/src/services/base/DatabaseService.d.ts @@ -0,0 +1,37 @@ +import type { IDatabaseService, IPathService, IVaultService, openDatabaseParameters } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import { LiveSyncLocalDB } from "@lib/pouchdb/LiveSyncLocalDB"; +import type { SettingService } from "./SettingService"; +import type { APIService } from "./APIService"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +export type DatabaseServiceDependencies = { + path: IPathService; + vault: IVaultService; + setting: SettingService; + API: APIService; +}; +/** + * The DatabaseService provides methods for managing the local database. + * Please note that each event of database lifecycle is handled in DatabaseEventService. + */ +export declare abstract class DatabaseService extends ServiceBase implements IDatabaseService { + _log: (msg: unknown, level?: import("octagonal-wheels/common/logger").LOG_LEVEL, key?: string) => void; + constructor(context: T, dependencies: DatabaseServiceDependencies); + protected _localDatabase: LiveSyncLocalDB | null; + protected services: DatabaseServiceDependencies; + onOpenDatabase: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(vaultName: string) => Promise>; + /** + * Called after the local database has been reset. + */ + onDatabaseReset: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + get localDatabase(): LiveSyncLocalDB; + get localDatabaseDirect(): LiveSyncLocalDB | null; + protected modifyDatabaseOptions(settings: ObsidianLiveSyncSettings, name: string, options: PouchDB.Configuration.DatabaseConfiguration): { + name: string; + options: PouchDB.Configuration.DatabaseConfiguration; + }; + createPouchDBInstance(name?: string, options?: PouchDB.Configuration.DatabaseConfiguration): PouchDB.Database; + openDatabase(params: openDatabaseParameters): Promise; + isDatabaseReady(): boolean; + resetDatabase(): Promise; +} diff --git a/_types/lib/src/services/base/FileProcessingService.d.ts b/_types/lib/src/services/base/FileProcessingService.d.ts new file mode 100644 index 0000000..1e198b6 --- /dev/null +++ b/_types/lib/src/services/base/FileProcessingService.d.ts @@ -0,0 +1,25 @@ +import type { IFileProcessingService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +/** + * File processing service handles file events and processes them accordingly. + */ +export declare class FileProcessingService extends ServiceBase implements IFileProcessingService { + /** + * Process a file event item by the registered handlers. + */ + readonly processFileEvent: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(item: import("../../common/types").FileEventItem) => Promise>; + /** + * Process a file event item optionally, if any handler is registered. + * i.e., hidden files synchronisation or customisation sync. + */ + readonly processOptionalFileEvent: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(path: import("../../common/settingConstants").FilePath) => Promise>; + /** + * Commit any pending file events that have been queued for processing. + */ + readonly commitPendingFileEvents: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + batched: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + totalQueued: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + processing: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + totalStorageFileEventCount: number; + onStorageFileEvent(): void; +} diff --git a/_types/lib/src/services/base/IService.d.ts b/_types/lib/src/services/base/IService.d.ts new file mode 100644 index 0000000..3d70b00 --- /dev/null +++ b/_types/lib/src/services/base/IService.d.ts @@ -0,0 +1,282 @@ +import type { FetchHttpHandler } from "@smithy/fetch-http-handler"; +import { type LOG_LEVEL } from "octagonal-wheels/common/logger"; +import type { AnyEntry, DocumentID, EntryHasPath, FilePath, FilePathWithPrefix, LoadedEntry, MetaEntry } from "@lib/common/models/db.type"; +import type { AUTO_MERGED, MISSING_OR_ERROR } from "@lib/common/models/shared.const.symbols"; +import type { CouchDBCredentials } from "@lib/common/models/auth.type"; +import type { diff_result } from "@lib/common/models/diff.definition"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { FileEventItem, UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { ObsidianLiveSyncSettings, RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import type { LiveSyncLocalDB } from "@lib/pouchdb/LiveSyncLocalDB"; +import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator"; +import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase"; +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive"; +import type { ReplicationStatics } from "@lib/common/models/shared.definition"; +import type { ReplicatorService } from "./ReplicatorService"; +import type { DatabaseEventService } from "./DatabaseEventService"; +import type { BASE_IS_NEW, EVEN, TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols"; +declare global { + interface OPTIONAL_SYNC_FEATURES { + DISABLE: "DISABLE"; + } +} +export interface ICommandCompat { + id: string; + name: string; + icon?: string; + callback?: () => any; + checkCallback?: (checking: boolean) => boolean | void; + editorCallback?: (editor: any, ctx: any) => any; + editorCheckCallback?: (checking: any, editor: any, ctx: any) => boolean | void; +} +export interface IAPIService { + getCustomFetchHandler(): FetchHttpHandler; + addStatusBarItem(): HTMLElement | undefined; + addLog(message: unknown, level: LOG_LEVEL, key?: string): void; + isMobile(): boolean; + showWindow(type: string): Promise; + showWindowOnRight?(type: string): Promise; + getAppID(): string; + getSystemVaultName(): string; + getPlatform(): string; + getAppVersion(): string; + getPluginVersion(): string; + addCommand(command: TCommand): TCommand; + registerWindow(type: string, factory: (leaf: any) => any): void; + addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement; + registerProtocolHandler(action: string, handler: (params: Record) => any): void; + confirm: Confirm; + responseCount: ReactiveSource; + requestCount: ReactiveSource; + isOnline: boolean; + webCompatFetch(url: string | Request, opts?: RequestInit): Promise; + nativeFetch(url: string | Request, opts?: RequestInit): Promise; + setInterval(handler: () => void, timeout: number): number; + clearInterval(timerId: number): void; + getSystemConfigDir(): string; +} +export interface IPathService { + id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix; + path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise; + getPath(entry: AnyEntry): FilePathWithPrefix; + markChangesAreSame(old: UXFileInfo | AnyEntry | FilePathWithPrefix, newMtime: number, oldMtime: number): boolean | undefined; + unmarkChanges(file: AnyEntry | FilePathWithPrefix | UXFileInfoStub): void; + compareFileFreshness(baseFile: UXFileInfoStub | AnyEntry | undefined, checkTarget: UXFileInfo | AnyEntry | undefined): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; + isMarkedAsSameChanges(file: UXFileInfoStub | AnyEntry | FilePathWithPrefix, mtimes: number[]): undefined | typeof EVEN; +} +export interface openDatabaseParameters { + replicator: ReplicatorService; + databaseEvents: DatabaseEventService; +} +export interface IDatabaseService { + localDatabase: LiveSyncLocalDB; + createPouchDBInstance(name?: string, options?: PouchDB.Configuration.DatabaseConfiguration): PouchDB.Database; + openDatabase(params: openDatabaseParameters): Promise; + resetDatabase(): Promise; + onDatabaseReset: () => Promise; + onOpenDatabase: (vaultName: string) => Promise; + isDatabaseReady(): boolean; +} +export interface IDatabaseEventService { + onUnloadDatabase(db: LiveSyncLocalDB): Promise; + onCloseDatabase(db: LiveSyncLocalDB): Promise; + onDatabaseInitialisation(db: LiveSyncLocalDB): Promise; + onDatabaseInitialised(showNotice: boolean): Promise; + onDatabaseHasReady(): Promise; + onResetDatabase(db: LiveSyncLocalDB): Promise; + initialiseDatabase(showingNotice?: boolean, reopenDatabase?: boolean, ignoreSuspending?: boolean): Promise; +} +export interface IKeyValueDBService { + openSimpleStore(kind: string): SimpleStore; + simpleStore: SimpleStore; +} +export interface IFileProcessingService { + processFileEvent(item: FileEventItem): Promise; + processOptionalFileEvent(path: FilePath): Promise; + commitPendingFileEvents(): Promise; + batched: ReactiveSource; + processing: ReactiveSource; + totalQueued: ReactiveSource; + totalStorageFileEventCount: number; + onStorageFileEvent(): void; +} +export interface IReplicatorService { + onCloseActiveReplication(): Promise; + onReplicatorInitialised(): Promise; + getNewReplicator(settingOverride?: Partial): Promise; + getActiveReplicator(): LiveSyncAbstractReplicator | undefined; + replicationStatics: ReactiveSource; +} +export interface IReplicationService { + processSynchroniseResult(doc: MetaEntry): Promise; + processOptionalSynchroniseResult(doc: LoadedEntry): Promise; + processVirtualDocument(docs: PouchDB.Core.ExistingDocument): Promise; + onBeforeReplicate(showMessage: boolean): Promise; + checkConnectionFailure(): Promise; + onCheckReplicationReady(showMessage: boolean): Promise; + isReplicationReady(showMessage: boolean): Promise; + performReplication(showMessage?: boolean): Promise; + replicate(showMessage?: boolean): Promise; + replicateByEvent(showMessage?: boolean): Promise; + onReplicationFailed(showMessage?: boolean): Promise; + parseSynchroniseResult(docs: Array>): Promise; + databaseQueueCount: ReactiveSource; + storageApplyingCount: ReactiveSource; + replicationResultCount: ReactiveSource; + replicateAllToRemote(showingNotice?: boolean, sendChunksInBulkDisabled?: boolean): Promise; + replicateAllFromRemote(showingNotice?: boolean): Promise; + markLocked(lockByClean?: boolean): Promise; + markUnlocked(): Promise; + markResolved(): Promise; +} +export interface IRemoteService { + connect(uri: string, auth: CouchDBCredentials, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean, performSetup: boolean, skipInfo: boolean, compression: boolean, customHeaders: Record, useRequestAPI: boolean, getPBKDF2Salt: () => Promise>): Promise; + info: PouchDB.Core.DatabaseInfo; + }>; + /** + * State if the last POST request failed due to payload size. + */ + get hadLastPostFailedBySize(): boolean; +} +export interface IConflictService { + getOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise; + resolveByUserInteraction: (filename: FilePathWithPrefix, conflictCheckResult: diff_result) => Promise; + queueCheckForIfOpen(path: FilePathWithPrefix): Promise; + queueCheckFor(path: FilePathWithPrefix): Promise; + ensureAllProcessed(): Promise; + resolveByDeletingRevision(path: FilePathWithPrefix, deleteRevision: string, title: string): Promise; + resolve(filename: FilePathWithPrefix): Promise; + resolveByNewest(filename: FilePathWithPrefix): Promise; + resolveAllConflictedFilesByNewerOnes(): Promise; + conflictProcessQueueCount: ReactiveSource; +} +export interface IAppLifecycleService { + onLayoutReady(): Promise; + onFirstInitialise(): Promise; + onReady(): Promise; + onWireUpEvents(): Promise; + onInitialise(): Promise; + onLoad(): Promise; + onSettingLoaded(): Promise; + onLoaded(): Promise; + onScanningStartupIssues(): Promise; + onAppUnload(): Promise; + onBeforeUnload(): Promise; + onUnload(): Promise; + onSuspending(): Promise; + onResuming(): Promise; + onResumed(): Promise; + getUnresolvedMessages: () => Promise<(string | Error)[][]>; + performRestart(): void; + askRestart(message?: string): void; + scheduleRestart(): void; + isSuspended(): boolean; + setSuspended(suspend: boolean): void; + isReady(): boolean; + markIsReady(): void; + resetIsReady(): void; + isReloadingScheduled(): boolean; +} +export interface ISettingService { + onBeforeRealiseSetting(): Promise; + onSettingRealised(): Promise; + onRealiseSetting(): Promise; + suspendAllSync(): Promise; + suspendExtraSync(): Promise; + suggestOptionalFeatures(opt: { + enableFetch?: boolean; + enableOverwrite?: boolean; + }): Promise; + enableOptionalFeature(mode: keyof OPTIONAL_SYNC_FEATURES): Promise; + clearUsedPassphrase(): void; + decryptSettings(settings: ObsidianLiveSyncSettings): Promise; + adjustSettings(settings: ObsidianLiveSyncSettings): Promise; + loadSettings(): Promise; + getDeviceAndVaultName(): string; + setDeviceAndVaultName(name: string): void; + saveDeviceAndVaultName(): void; + onBeforeSaveSettingData(nextSettings: ObsidianLiveSyncSettings, previousSettings: ObsidianLiveSyncSettings): Promise<(Partial | void)[]>; + saveSettingData(): Promise; + currentSettings(): ObsidianLiveSyncSettings; + updateSettings(updateFn: (current: ObsidianLiveSyncSettings) => ObsidianLiveSyncSettings, saveImmediately?: boolean): Promise; + applyExternalSettings(partial: Partial, saveImmediately?: boolean): Promise; + applyPartial(partial: Partial, saveImmediately?: boolean): Promise; + onSettingLoaded(settings: ObsidianLiveSyncSettings): Promise; + onSettingChanged(settings: ObsidianLiveSyncSettings): Promise; + onSettingSaved(settings: ObsidianLiveSyncSettings): Promise; + getSmallConfig(key: string): string | null; + setSmallConfig(key: string, value: string): void; + deleteSmallConfig(key: string): void; +} +export interface ITweakValueService { + fetchRemotePreferred(trialSetting: RemoteDBSettings): Promise; + checkAndAskResolvingMismatched(preferred: Partial): Promise<[TweakValues | boolean, boolean]>; + askResolvingMismatched(preferredSource: TweakValues): Promise<"OK" | "CHECKAGAIN" | "IGNORE">; + checkAndAskUseRemoteConfiguration(settings: RemoteDBSettings): Promise<{ + result: false | TweakValues; + requireFetch: boolean; + }>; + askUseRemoteConfiguration(trialSetting: RemoteDBSettings, preferred: TweakValues): Promise<{ + result: false | TweakValues; + requireFetch: boolean; + }>; +} +export interface IVaultService { + vaultName(): string; + getVaultName(): string; + scanVault(showingNotice?: boolean, ignoreSuspending?: boolean): Promise; + isIgnoredByIgnoreFile(file: string | UXFileInfoStub): Promise; + isTargetFile(file: string | UXFileInfoStub): Promise; + isTargetFileInExtra(file: string | UXFileInfoStub): Promise; + isFileSizeTooLarge(size: number): boolean; + getActiveFilePath(): FilePath | undefined; + isStorageInsensitive(): boolean; + shouldCheckCaseInsensitively(): boolean; + isValidPath(path: string): boolean; +} +export interface ITestService { + test(): Promise; + testMultiDevice(): Promise; + addTestResult(name: string, key: string, result: boolean, summary?: string, message?: string): void; +} +export interface IUIService { + promptCopyToClipboard(title: string, value: string): Promise; + showMarkdownDialog(title: string, contentMD: string, buttons: T): Promise<(typeof buttons)[number] | false>; + get confirm(): Confirm; +} +export interface IConfigService { + getSmallConfig(key: string): string | null; + setSmallConfig(key: string, value: string): void; + deleteSmallConfig(key: string): void; +} +export interface IServiceHub { + API: IAPIService; + path: IPathService; + database: IDatabaseService; + databaseEvents: IDatabaseEventService; + replicator: IReplicatorService; + fileProcessing: IFileProcessingService; + replication: IReplicationService; + remote: IRemoteService; + conflict: IConflictService; + appLifecycle: IAppLifecycleService; + setting: ISettingService; + tweakValue: ITweakValueService; + vault: IVaultService; + test: ITestService; + UI: IUIService; + config: IConfigService; + keyValueDB: IKeyValueDBService; + control: IControlService; +} +export interface IControlService { + applySettings(): Promise; + onLoad(): Promise; + onReady(): Promise; + onUnload(): Promise; + hasUnloaded(): boolean; + activated: Promise; +} diff --git a/_types/lib/src/services/base/KeyValueDBService.d.ts b/_types/lib/src/services/base/KeyValueDBService.d.ts new file mode 100644 index 0000000..c1a1528 --- /dev/null +++ b/_types/lib/src/services/base/KeyValueDBService.d.ts @@ -0,0 +1,40 @@ +import type { SimpleStore } from "@lib/common/utils"; +import type { IKeyValueDBService, IVaultService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import type { KeyValueDatabase } from "@lib/interfaces/KeyValueDatabase"; +import type { InjectableDatabaseEventService } from "@lib/services/implements/injectable/InjectableDatabaseEventService"; +import type { AppLifecycleServiceBase } from "@lib/services/implements/injectable/InjectableAppLifecycleService"; +export interface KeyValueDBDependencies { + databaseEvents: InjectableDatabaseEventService; + vault: IVaultService; + appLifecycle: AppLifecycleServiceBase; +} +/** + * The KeyValueDBService provides methods for managing the local key-value database. + * Please note that each event of database lifecycle is handled in DatabaseEventService. + */ +export declare abstract class KeyValueDBService extends ServiceBase implements IKeyValueDBService { + private _kvDB; + private _simpleStore; + get simpleStore(): SimpleStore; + get kvDB(): KeyValueDatabase; + private databaseEvents; + private vault; + private appLifecycle; + private _log; + private _everyOnResetDatabase; + private tryCloseKvDB; + private openKeyValueDB; + private _onOtherDatabaseUnload; + private _onOtherDatabaseClose; + private _everyOnInitializeDatabase; + private _everyOnloadAfterLoadSettings; + constructor(context: T, dependencies: KeyValueDBDependencies); + openSimpleStore(kind: string): { + get: (key: string) => Promise; + set: (key: string, value: unknown) => Promise; + delete: (key: string) => Promise; + keys: (from: string | undefined, to: string | undefined, count?: number) => Promise; + db: Promise; + }; +} diff --git a/_types/lib/src/services/base/PathService.d.ts b/_types/lib/src/services/base/PathService.d.ts new file mode 100644 index 0000000..b9630d9 --- /dev/null +++ b/_types/lib/src/services/base/PathService.d.ts @@ -0,0 +1,39 @@ +import type { DocumentID, EntryHasPath, FilePathWithPrefix, FilePath, AnyEntry } from "@lib/common/models/db.type"; +import type { UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { IPathService, ISettingService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import type { BASE_IS_NEW, EVEN, TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols"; +export interface PathServiceDependencies { + settingService: ISettingService; +} +/** + * The PathService provides methods for converting between file paths and document IDs. + * This class would be migrated to the new logic later. + */ +export declare abstract class PathService extends ServiceBase implements IPathService { + protected settingService: ISettingService; + protected abstract normalizePath(path: string): string; + get settings(): import("../../common/types").ObsidianLiveSyncSettings; + constructor(context: T, dependencies: PathServiceDependencies); + private _id2path; + private _path2id; + /** + * Convert a document ID or entry to a virtual file path. + * @param id A document ID. Nowadays, it is mostly not the same as the file path. + * If the document has `_` prefixed, saved as `/_`. + * @param entry An entry object. If provided, it can be used to get the path directly. + * @param stripPrefix Whether to strip the prefix from the path. + */ + id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix; + /** + * Convert a virtual file path to a document ID (with prefix if any). + * @param filename A file path with or without prefix. + * @param prefix The prefix to use for the document ID. + */ + path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise; + getPath(entry: AnyEntry): FilePathWithPrefix; + abstract markChangesAreSame(old: UXFileInfo | AnyEntry | FilePathWithPrefix, newMtime: number, oldMtime: number): boolean | undefined; + abstract unmarkChanges(file: AnyEntry | FilePathWithPrefix | UXFileInfoStub): void; + abstract compareFileFreshness(baseFile: UXFileInfoStub | AnyEntry | undefined, checkTarget: UXFileInfo | AnyEntry | undefined): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; + abstract isMarkedAsSameChanges(file: UXFileInfoStub | AnyEntry | FilePathWithPrefix, mtimes: number[]): undefined | typeof EVEN; +} diff --git a/_types/lib/src/services/base/RemoteService.d.ts b/_types/lib/src/services/base/RemoteService.d.ts new file mode 100644 index 0000000..d56f6db --- /dev/null +++ b/_types/lib/src/services/base/RemoteService.d.ts @@ -0,0 +1,58 @@ +import type { CouchDBCredentials } from "@lib/common/models/auth.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { IRemoteService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import type { LOG_LEVEL } from "@lib/common/logger"; +import { AuthorizationHeaderGenerator } from "@lib/replication/httplib"; +import type { APIService } from "./APIService"; +import type { AppLifecycleService } from "./AppLifecycleService"; +import type { SettingService } from "./SettingService"; +import { UnresolvedErrorManager } from "./UnresolvedErrorManager"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +export interface RemoteServiceDependencies { + APIService: APIService; + appLifecycle: AppLifecycleService; + setting: SettingService; +} +declare const FetchMethod: { + readonly webCompat: 0; + readonly native: 1; +}; +type FetchMethod = (typeof FetchMethod)[keyof typeof FetchMethod]; +/** + * The RemoteService provides methods for interacting with the remote database. + */ +export declare abstract class RemoteService extends ServiceBase implements IRemoteService { + /** + * Connect to the remote database with the provided settings. + * @param uri The URI of the remote database. + * @param auth The authentication credentials for the remote database. + * @param disableRequestURI Whether to disable the request URI. + * @param passphrase The passphrase for the remote database. + * @param useDynamicIterationCount Whether to use dynamic iteration count. + * @param performSetup Whether to perform setup. + * @param skipInfo Whether to skip information retrieval. + * @param compression Whether to enable compression. + * @param customHeaders Custom headers to include in the request. + * @param useRequestAPI Whether to use the request API. + * @param getPBKDF2Salt Function to retrieve the PBKDF2 salt. + * Note that this function is used for CouchDB and compatible only. + */ + protected _log: LogFunction; + protected _authHeader: AuthorizationHeaderGenerator; + protected _APIService: APIService; + protected _appLifecycleService: AppLifecycleService; + protected _settingService: SettingService; + protected _unresolvedErrors: UnresolvedErrorManager; + protected last_successful_post: boolean; + get hadLastPostFailedBySize(): boolean; + constructor(context: T, dependencies: RemoteServiceDependencies); + showError(msg: string, max_log_level?: LOG_LEVEL): void; + clearErrors(): void; + performFetch(req: string | Request, opts?: RequestInit, fetchMethod?: FetchMethod): Promise; + connect(uri: string, auth: CouchDBCredentials, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean, performSetup: boolean, skipInfo: boolean, compression: boolean, customHeaders: Record, useRequestAPI: boolean, getPBKDF2Salt: () => Promise>): Promise; + info: PouchDB.Core.DatabaseInfo; + }>; +} +export {}; diff --git a/_types/lib/src/services/base/ReplicationService.d.ts b/_types/lib/src/services/base/ReplicationService.d.ts new file mode 100644 index 0000000..fc6bb46 --- /dev/null +++ b/_types/lib/src/services/base/ReplicationService.d.ts @@ -0,0 +1,91 @@ +import type { LOG_LEVEL } from "@lib/common/logger"; +import type { IAPIService, IDatabaseService, IFileProcessingService, IReplicationService, IReplicatorService, ISettingService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator"; +import type { AppLifecycleService } from "./AppLifecycleService"; +export interface ReplicationServiceDependencies { + APIService: IAPIService; + settingService: ISettingService; + appLifecycleService: AppLifecycleService; + databaseService: IDatabaseService; + replicatorService: IReplicatorService; + fileProcessingService: IFileProcessingService; +} +/** + * The ReplicationService provides methods for managing replication processes. + */ +export declare abstract class ReplicationService extends ServiceBase implements IReplicationService { + private _unresolvedErrorManager; + showError(msg: string, max_log_level?: LOG_LEVEL): void; + clearErrors(): void; + _log: LogFunction; + settingService: ISettingService; + appLifecycleService: AppLifecycleService; + replicatorService: IReplicatorService; + APIService: IAPIService; + fileProcessing: IFileProcessingService; + databaseService: IDatabaseService; + constructor(context: T, dependencies: ReplicationServiceDependencies); + /** + * Process a synchronisation result document. + */ + readonly processSynchroniseResult: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(doc: import("../../common/types").MetaEntry) => Promise>; + /** + * Process a synchronisation result document for optional entries i.e., hidden files. + */ + readonly processOptionalSynchroniseResult: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(doc: import("../../common/types").LoadedEntry) => Promise>; + /** + * Process an array of synchronisation result documents. + * @param docs An array of documents to parse and handle. + */ + readonly parseSynchroniseResult: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(docs: Array>) => Promise>; + /** + * Process a virtual document (e.g., for customisation sync). + */ + readonly processVirtualDocument: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(docs: PouchDB.Core.ExistingDocument) => Promise>; + /** + * An event triggered before starting replication. + */ + readonly onBeforeReplicate: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(showMessage: boolean) => Promise>; + /** + * + */ + readonly onCheckReplicationReady: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(showMessage: boolean) => Promise>; + /** + * Check if the replication is ready to start. + * @param showMessage Whether to show messages to the user. + */ + isReplicationReady(showMessage?: boolean): Promise; + onReplicationFailed: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(showMessage?: boolean) => Promise>; + /** + * perform replication. The actual replication logic should be implemented in the handler of this event. + * @param showMessage + */ + performReplication(showMessage?: boolean): Promise; + /** + * Start the replication process. + * @param showMessage Whether to show messages to the user. + */ + replicate(showMessage?: boolean): Promise; + previousReplicated: number; + /** + * Start the replication process triggered by an event (e.g., file change). + * @param showMessage Whether to show messages to the user. + */ + replicateByEvent(showMessage?: boolean): Promise; + /** + * Check if there is a connection failure with the remote database. + */ + readonly checkConnectionFailure: import("@lib/services/lib/HandlerUtils").MultipleHandlerFunction<() => Promise, any>; + databaseQueueCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + storageApplyingCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + replicationResultCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + getActiveReplicatorFor(usage: string): false | LiveSyncAbstractReplicator; + replicateAllToRemote(showingNotice?: boolean, sendChunksInBulkDisabled?: boolean): Promise; + replicateAllFromRemote(showingNotice?: boolean): Promise; + private _getReplicatorAndPerform; + markLocked(lockByClean?: boolean): Promise; + markUnlocked(): Promise; + markResolved(): Promise; +} diff --git a/_types/lib/src/services/base/ReplicatorService.d.ts b/_types/lib/src/services/base/ReplicatorService.d.ts new file mode 100644 index 0000000..e4970a8 --- /dev/null +++ b/_types/lib/src/services/base/ReplicatorService.d.ts @@ -0,0 +1,54 @@ +import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator"; +import type { IReplicatorService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import type { SettingService } from "./SettingService"; +import type { AppLifecycleService } from "./AppLifecycleService"; +import { UnresolvedErrorManager } from "./UnresolvedErrorManager"; +import type { DatabaseEventService } from "./DatabaseEventService"; +export interface ReplicatorServiceDependencies { + settingService: SettingService; + appLifecycleService: AppLifecycleService; + databaseEventService: DatabaseEventService; +} +/** + * The ReplicatorService provides methods for managing replication. + */ +export declare abstract class ReplicatorService extends ServiceBase implements IReplicatorService { + protected dependencies: ReplicatorServiceDependencies; + _log: (msg: unknown, level?: import("octagonal-wheels/common/logger").LOG_LEVEL, key?: string) => void; + private settingService; + private databaseEventService; + private _activeReplicator; + private _replicatorType; + private appLifecycleService; + _unresolvedErrorManager: UnresolvedErrorManager; + constructor(context: T, dependencies: ReplicatorServiceDependencies); + private suspendReplication; + private reinitialiseReplicator; + private disposeReplicator; + private _initialiseReplicator; + /** + * Close the active replication if any. + * Not used currently. + */ + readonly onCloseActiveReplication: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Get a new replicator instance based on the provided settings. + */ + readonly getNewReplicator: import("@lib/services/lib/HandlerUtils").MultipleHandlerFunction<(settingOverride?: Partial) => Promise, any>; + readonly onReplicatorInitialised: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Get the currently active replicator instance. + * If no active replicator, return undefined but that is the fatal situation (on Obsidian). + */ + getActiveReplicator(): LiveSyncAbstractReplicator | undefined; + replicationStatics: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource<{ + sent: number; + arrived: number; + maxPullSeq: number; + maxPushSeq: number; + lastSyncPullSeq: number; + lastSyncPushSeq: number; + syncStatus: import("@lib/common/models/shared.definition").DatabaseConnectingStatus; + }>; +} diff --git a/_types/lib/src/services/base/ServiceBase.d.ts b/_types/lib/src/services/base/ServiceBase.d.ts new file mode 100644 index 0000000..2922a53 --- /dev/null +++ b/_types/lib/src/services/base/ServiceBase.d.ts @@ -0,0 +1,6 @@ +export declare class ServiceContext { +} +export declare abstract class ServiceBase { + protected context: T; + constructor(context: T); +} diff --git a/_types/lib/src/services/base/SettingService.d.ts b/_types/lib/src/services/base/SettingService.d.ts new file mode 100644 index 0000000..d3b46d8 --- /dev/null +++ b/_types/lib/src/services/base/SettingService.d.ts @@ -0,0 +1,112 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import type { IAPIService, ISettingService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +import { createInstanceLogFunction } from "@lib/services/lib/logUtils"; +export interface SettingServiceDependencies { + APIService: IAPIService; +} +export declare abstract class SettingService extends ServiceBase implements ISettingService { + deviceAndVaultName: string; + protected APIService: IAPIService; + protected abstract setItem(key: string, value: string): void; + protected abstract getItem(key: string): string; + protected abstract deleteItem(key: string): void; + _settings: ObsidianLiveSyncSettings; + get settings(): ObsidianLiveSyncSettings; + set settings(value: ObsidianLiveSyncSettings); + protected abstract saveData(setting: ObsidianLiveSyncSettings): Promise; + protected abstract loadData(): Promise; + private _lastPersistedSettings?; + _log: ReturnType; + constructor(context: T, dependencies: SettingServiceDependencies); + /** + * Adjust the given settings, e.g., migrate old settings to new format. + * @param settings The settings to adjust. + */ + adjustSettings(settings: ObsidianLiveSyncSettings): Promise; + /** + * Get the unique name for identify the device. + */ + getDeviceAndVaultName(): string; + /** + * Set the unique name for identify the device. + * @param name The unique name to set. + */ + setDeviceAndVaultName(name: string): void; + /** + * Save the current device and vault name to settings, aside from the main settings. + */ + saveDeviceAndVaultName(): void; + private additionalSuffixOfDatabaseName; + private getKey; + setSmallConfig(key: string, value: string): void; + getSmallConfig(key: string): string; + deleteSmallConfig(key: string): void; + /** + * Save the current settings to storage. + */ + saveSettingData(): Promise; + private encryptRemoteConfigurationUris; + private decryptRemoteConfigurationUris; + /** + * Event triggered before realising the settings. + * Handlers can return false to abort the realisation process. + */ + readonly onBeforeRealiseSetting: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered after the settings have been realised. + */ + readonly onSettingRealised: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Event triggered to realise the settings. + */ + readonly onRealiseSetting: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Suspend all synchronisation activities and save to the settings. + */ + readonly suspendAllSync: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Suspend extra synchronisation activities, e.g., hidden files sync. + */ + readonly suspendExtraSync: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Suggest enabling optional features to the user. + */ + readonly suggestOptionalFeatures: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(opt: { + enableFetch?: boolean; + enableOverwrite?: boolean; + }) => Promise>; + /** + * Enable an optional feature and save to the settings. + * It may also raised from `handleSuggestOptionalFeatures` if the user agrees. + * @param mode The optional feature to enable. + */ + readonly enableOptionalFeature: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(mode: keyof OPTIONAL_SYNC_FEATURES) => Promise>; + readonly onSettingLoaded: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(settings: ObsidianLiveSyncSettings) => Promise>; + readonly onSettingChanged: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(settings: ObsidianLiveSyncSettings) => Promise>; + readonly onSettingSaved: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(settings: ObsidianLiveSyncSettings) => Promise>; + readonly onBeforeSaveSettingData: import("@lib/services/lib/HandlerUtils").CollectiveHandlerFunction<(nextSettings: ObsidianLiveSyncSettings, previousSettings: ObsidianLiveSyncSettings) => Promise<(Partial | void)[]>, any>; + /** + * Get the current settings. + */ + currentSettings(): ObsidianLiveSyncSettings; + updateSettings(updateFn: (settings: ObsidianLiveSyncSettings) => ObsidianLiveSyncSettings, saveImmediately?: boolean): Promise; + applyExternalSettings(partial: Partial, saveImmediately?: boolean): Promise; + applyPartial(partial: Partial, saveImmediately?: boolean): Promise; + getPassphrase(settings: ObsidianLiveSyncSettings): Promise; + private usedPassphrase; + /** + * Clear any used passphrase from memory. + */ + clearUsedPassphrase(): void; + decryptConfigurationItem(encrypted: string, passphrase: string): Promise; + encryptConfigurationItem(src: string, settings: ObsidianLiveSyncSettings): Promise; + /** + * Decrypt the given settings. + * @param settings The settings to decrypt. + */ + decryptSettings(settings: ObsidianLiveSyncSettings): Promise; + loadSettings(): Promise; + private tryDecodeJson; + private cloneSettings; +} diff --git a/_types/lib/src/services/base/TestService.d.ts b/_types/lib/src/services/base/TestService.d.ts new file mode 100644 index 0000000..76d8e9d --- /dev/null +++ b/_types/lib/src/services/base/TestService.d.ts @@ -0,0 +1,28 @@ +import type { ITestService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +/** + * The TestService provides methods for adding and handling test results. + */ +export declare abstract class TestService extends ServiceBase implements ITestService { + /** + * Run the test suite to verify the plug-in's functionality. + * This is typically used for development and debugging purposes. + * It may involve user interaction (means raising resolveByUserInteraction). + */ + readonly test: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Run the multi-device test suite to verify the plug-in's functionality across multiple devices. + * This is typically used for development and debugging purposes. + * It may involve user interaction (means raising resolveByUserInteraction). + */ + readonly testMultiDevice: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<() => Promise>; + /** + * Add a test result to the test suite. + * @param name The name of the test case. + * @param key The key of the test result. + * @param result The result of the test (true for success, false for failure). + * @param summary A brief summary of the test result. + * @param message A detailed message about the test result. + */ + abstract addTestResult(name: string, key: string, result: boolean, summary?: string, message?: string): void; +} diff --git a/_types/lib/src/services/base/TweakValueService.d.ts b/_types/lib/src/services/base/TweakValueService.d.ts new file mode 100644 index 0000000..c92cc9b --- /dev/null +++ b/_types/lib/src/services/base/TweakValueService.d.ts @@ -0,0 +1,41 @@ +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import type { ITweakValueService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +/** + * The TweakValueService provides methods for managing tweak values and resolving mismatches. + */ +export declare abstract class TweakValueService extends ServiceBase implements ITweakValueService { + /** + * Fetch and trial the remote database settings to determine if they are preferred. + * @param trialSetting The remote database settings to connect. + */ + abstract fetchRemotePreferred(trialSetting: RemoteDBSettings): Promise; + /** + * Check and ask the user to resolve any mismatched tweak values. + * @param preferred The preferred tweak values to check against. + */ + abstract checkAndAskResolvingMismatched(preferred: Partial): Promise<[TweakValues | boolean, boolean]>; + /** + * Ask the user to resolve any mismatched tweak values. + * @param preferredSource The preferred tweak values to resolve against. + */ + abstract askResolvingMismatched(preferredSource: TweakValues): Promise<"OK" | "CHECKAGAIN" | "IGNORE">; + /** + * Check and ask the user to use the remote configuration. + * @param settings The remote database settings to connect. + */ + abstract checkAndAskUseRemoteConfiguration(settings: RemoteDBSettings): Promise<{ + result: false | TweakValues; + requireFetch: boolean; + }>; + /** + * Ask the user to use the remote configuration. + * @param trialSetting The remote database settings to connect. + * @param preferred The preferred tweak values to use. + */ + abstract askUseRemoteConfiguration(trialSetting: RemoteDBSettings, preferred: TweakValues): Promise<{ + result: false | TweakValues; + requireFetch: boolean; + }>; +} diff --git a/_types/lib/src/services/base/UnresolvedErrorManager.d.ts b/_types/lib/src/services/base/UnresolvedErrorManager.d.ts new file mode 100644 index 0000000..6aea765 --- /dev/null +++ b/_types/lib/src/services/base/UnresolvedErrorManager.d.ts @@ -0,0 +1,13 @@ +import { type LOG_LEVEL } from "octagonal-wheels/common/logger"; +import type { AppLifecycleService } from "./AppLifecycleService"; +export declare class UnresolvedErrorManager { + private _log; + private appLifecycleService; + private _occurredErrors; + showError(msg: string, max_log_level?: LOG_LEVEL): void; + clearError(msg: string): void; + clearErrors(): void; + countErrors(needle: string): number; + private _reportUnresolvedMessages; + constructor(appLifecycleService: AppLifecycleService); +} diff --git a/_types/lib/src/services/base/VaultService.d.ts b/_types/lib/src/services/base/VaultService.d.ts new file mode 100644 index 0000000..5ad913e --- /dev/null +++ b/_types/lib/src/services/base/VaultService.d.ts @@ -0,0 +1,69 @@ +import type { FilePath } from "@lib/common/models/db.type"; +import type { IAPIService, ISettingService, IVaultService } from "./IService"; +import { ServiceBase, type ServiceContext } from "./ServiceBase"; +export interface VaultServiceDependencies { + settingService: ISettingService; + APIService: IAPIService; +} +/** + * The VaultService provides methods for interacting with the vault (local file system). + */ +export declare abstract class VaultService extends ServiceBase implements IVaultService { + protected settingService: ISettingService; + protected APIService: IAPIService; + get settings(): import("../../common/types").ObsidianLiveSyncSettings; + constructor(context: T, dependencies: VaultServiceDependencies); + /** + * Get the vault name only. + */ + vaultName(): string; + /** + * Get the vault name with additional suffixes. + */ + getVaultName(): string; + /** + * Scan the vault for changes (especially for changes during the plug-in were not running). + * @param showingNotice Whether to show a notice to the user. + * @param ignoreSuspending Whether to ignore any suspending state. + */ + readonly scanVault: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(showingNotice?: boolean, ignoreSuspending?: boolean) => Promise>; + /** + * Check if a file is ignored by the ignore file (e.g., .gitignore, .obsidianignore). + * @param file The file path or file info stub to check. + */ + readonly isIgnoredByIgnoreFile: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(file: string | import("../../common/types").UXFileInfoStub) => Promise>; + /** + * Check if a file is a target file for synchronisation. + * @param file The file path or file info stub to check. + * @param keepFileCheckList Whether to keep the file in the check list. + */ + readonly isTargetFile: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(file: string | import("../../common/types").UXFileInfoStub) => Promise>; + /** + * Check if a file is a target file for some extra feature + */ + readonly isTargetFileInExtra: import("@lib/services/lib/HandlerUtils").BooleanMultipleHandlerFunction<(file: string | import("../../common/types").UXFileInfoStub) => Promise>; + /** + * Check if a filesize is too large against the current settings. + * @param size The file size to check. + */ + isFileSizeTooLarge(size: number): boolean; + /** + * Get the currently active file path in the editor, if any. + */ + abstract getActiveFilePath(): FilePath | undefined; + /** + * Check if the vault is on a case-insensitive file system. + * This is important for certain operating systems like Windows and macOS. + */ + abstract isStorageInsensitive(): boolean; + /** + * Check if the file system should be treated case-insensitively. + * This is important for certain operating systems like Windows and macOS. + */ + shouldCheckCaseInsensitively(): boolean; + /** + * Check if a given path is valid in the vault. + * @param path The file path to check. + */ + abstract isValidPath(path: string): boolean; +} diff --git a/_types/lib/src/services/implements/base/UIService.d.ts b/_types/lib/src/services/implements/base/UIService.d.ts new file mode 100644 index 0000000..86c8257 --- /dev/null +++ b/_types/lib/src/services/implements/base/UIService.d.ts @@ -0,0 +1,26 @@ +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { ComponentHasResult, SvelteDialogManagerBase } from "@lib/UI/svelteDialog"; +import type { IAPIService, IUIService } from "@lib/services/base/IService"; +import { type AppLifecycleService } from "@lib/services/base/AppLifecycleService.ts"; +import { ServiceBase, type ServiceContext } from "@lib/services/base/ServiceBase"; +export type UIServiceDependencies = { + appLifecycle: AppLifecycleService; + dialogManager: SvelteDialogManagerBase; + APIService: IAPIService; +}; +type DialogResult = "ok" | "cancel"; +type DialogParams = { + title: string; + dataToCopy: string; +}; +export declare abstract class UIService extends ServiceBase implements IUIService { + private _dialogManager; + protected _APIService: IAPIService; + abstract get dialogToCopy(): ComponentHasResult; + constructor(context: T, dependents: UIServiceDependencies); + get dialogManager(): SvelteDialogManagerBase; + promptCopyToClipboard(title: string, value: string): Promise; + showMarkdownDialog(title: string, contentMD: string, buttons: T, defaultAction?: (typeof buttons)[number]): Promise<(typeof buttons)[number] | false>; + get confirm(): Confirm; +} +export {}; diff --git a/_types/lib/src/services/implements/browser/BrowserAPIService.d.ts b/_types/lib/src/services/implements/browser/BrowserAPIService.d.ts new file mode 100644 index 0000000..bde0ca4 --- /dev/null +++ b/_types/lib/src/services/implements/browser/BrowserAPIService.d.ts @@ -0,0 +1,51 @@ +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { InjectableAPIService } from "@lib/services/implements/injectable/InjectableAPIService"; +import type { FetchHttpHandler } from "@smithy/fetch-http-handler"; +import type { ICommandCompat } from "../../base/IService"; +import type { Confirm } from "@lib/interfaces/Confirm"; +export declare const PACKAGE_VERSION: string; +export declare const MANIFEST_VERSION: string; +export declare class BrowserAPIService extends InjectableAPIService { + _confirmInstance: Confirm; + private commandBar; + private commandButtons; + private logPanel; + private logViewport; + private readonly maxLogLines; + private windowFactories; + private windowInstances; + private windowRoot; + private windowTabs; + private windowBody; + private windowPanels; + private activeWindowType; + constructor(context: T); + get confirm(): Confirm; + showWindow(type: string): Promise; + getCustomFetchHandler(): FetchHttpHandler; + isMobile(): boolean; + getAppID(): string; + getSystemVaultName: import("../../lib/HandlerUtils").HandlerFunction<() => string, any>; + getAppVersion(): string; + getPluginVersion(): string; + getPlatform(): string; + getCrypto(): Crypto; + nativeFetch(req: string | Request, opts?: RequestInit): Promise; + private ensureLogPanel; + private formatLogLine; + private appendLog; + private ensureCommandBar; + private ensureWindowHost; + private ensureWindowTab; + private ensureWindowPanel; + private activateWindow; + private createLeafShim; + private evaluateEnabled; + private executeCommand; + private refreshCommandStates; + addCommand(command: TCommand): TCommand; + addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement; + registerWindow(type: string, factory: (leaf: any) => any): void; + registerProtocolHandler(action: string, handler: (params: Record) => any): void; + addStatusBarItem(): HTMLElement | undefined; +} diff --git a/_types/lib/src/services/implements/browser/BrowserConfirm.d.ts b/_types/lib/src/services/implements/browser/BrowserConfirm.d.ts new file mode 100644 index 0000000..60ec64e --- /dev/null +++ b/_types/lib/src/services/implements/browser/BrowserConfirm.d.ts @@ -0,0 +1,21 @@ +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class BrowserConfirm implements Confirm { + _context: T; + constructor(context: T); + askYesNo(message: string): Promise<"yes" | "no">; + askString(title: string, key: string, placeholder: string, isPassword?: boolean): Promise; + askYesNoDialog(message: string, opt: { + title?: string; + defaultOption?: "Yes" | "No"; + timeout?: number; + }): Promise<"yes" | "no">; + askSelectString(message: string, items: string[]): Promise; + askSelectStringDialogue(message: string, buttons: T, opt: { + title?: string; + defaultAction: T[number]; + timeout?: number; + }): Promise; + askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void): void; + confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>; +} diff --git a/_types/lib/src/services/implements/browser/BrowserDatabaseService.d.ts b/_types/lib/src/services/implements/browser/BrowserDatabaseService.d.ts new file mode 100644 index 0000000..0b93560 --- /dev/null +++ b/_types/lib/src/services/implements/browser/BrowserDatabaseService.d.ts @@ -0,0 +1,7 @@ +import type { ServiceContext } from "../../base/ServiceBase"; +import { KeyValueDBService } from "../../base/KeyValueDBService"; +import { DatabaseService } from "@lib/services/base/DatabaseService.ts"; +export declare class BrowserDatabaseService extends DatabaseService { +} +export declare class BrowserKeyValueDBService extends KeyValueDBService { +} diff --git a/_types/lib/src/services/implements/browser/BrowserUIService.d.ts b/_types/lib/src/services/implements/browser/BrowserUIService.d.ts new file mode 100644 index 0000000..f2e4f9f --- /dev/null +++ b/_types/lib/src/services/implements/browser/BrowserUIService.d.ts @@ -0,0 +1,17 @@ +import { UIService } from "@lib/services/implements/base/UIService"; +import type { ConfigService } from "@lib/services/base/ConfigService"; +import type { AppLifecycleService } from "@lib/services/base/AppLifecycleService"; +import type { ReplicatorService } from "@lib/services/base/ReplicatorService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import type { IAPIService, IControlService } from "../../base/IService"; +export type BrowserUIServiceDependencies = { + appLifecycle: AppLifecycleService; + config: ConfigService; + replicator: ReplicatorService; + APIService: IAPIService; + control: IControlService; +}; +export declare class BrowserUIService extends UIService { + get dialogToCopy(): import("svelte/legacy").LegacyComponentType; + constructor(context: T, dependents: BrowserUIServiceDependencies); +} diff --git a/_types/lib/src/services/implements/browser/ConfigServiceBrowserCompat.d.ts b/_types/lib/src/services/implements/browser/ConfigServiceBrowserCompat.d.ts new file mode 100644 index 0000000..8e63ca0 --- /dev/null +++ b/_types/lib/src/services/implements/browser/ConfigServiceBrowserCompat.d.ts @@ -0,0 +1,16 @@ +import { ConfigService } from "@lib/services/base/ConfigService"; +import type { IAPIService, ISettingService } from "@lib/services/base/IService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { createInstanceLogFunction } from "@lib/services/lib/logUtils"; +export interface ConfigServiceBrowserCompatDependencies { + settingService: ISettingService; + APIService: IAPIService; +} +export declare class ConfigServiceBrowserCompat extends ConfigService { + private _settingService; + _log: ReturnType; + constructor(context: T, dependencies: ConfigServiceBrowserCompatDependencies); + getSmallConfig(key: string): string | null; + setSmallConfig(key: string, value: string): void; + deleteSmallConfig(key: string): void; +} diff --git a/_types/lib/src/services/implements/browser/Menu.d.ts b/_types/lib/src/services/implements/browser/Menu.d.ts new file mode 100644 index 0000000..b3c454b --- /dev/null +++ b/_types/lib/src/services/implements/browser/Menu.d.ts @@ -0,0 +1,26 @@ +import { type PromiseWithResolvers } from "octagonal-wheels/promises"; +export declare class MenuItem { + type: string; + title: string; + handler?: () => void | Promise; + icon: string; + setTitle(title: string): this; + onClick(callback: () => void | Promise): this; + setIcon(icon: string | null): this; +} +export declare class MenuSeparator { + type: string; +} +export declare class Menu { + type: string; + items: (MenuItem | MenuSeparator)[]; + constructor(); + addItem(callback: (item: MenuItem) => void): this; + addSeparator(): this; + waitingForClose?: PromiseWithResolvers; + showAtPosition(pos: { + x: number; + y: number; + }): Promise; + hide(): void; +} diff --git a/_types/lib/src/services/implements/browser/ui/renderMessageMarkdown.d.ts b/_types/lib/src/services/implements/browser/ui/renderMessageMarkdown.d.ts new file mode 100644 index 0000000..19675e6 --- /dev/null +++ b/_types/lib/src/services/implements/browser/ui/renderMessageMarkdown.d.ts @@ -0,0 +1 @@ +export declare function renderMessageMarkdown(message: string): string; diff --git a/_types/lib/src/services/implements/headless/HeadlessAPIService.d.ts b/_types/lib/src/services/implements/headless/HeadlessAPIService.d.ts new file mode 100644 index 0000000..00d4b94 --- /dev/null +++ b/_types/lib/src/services/implements/headless/HeadlessAPIService.d.ts @@ -0,0 +1,52 @@ +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { InjectableAPIService } from "@lib/services/implements/injectable/InjectableAPIService"; +import type { FetchHttpHandler } from "@smithy/fetch-http-handler"; +import type { ICommandCompat } from "../../base/IService"; +import type { Confirm } from "@lib/interfaces/Confirm"; +/** + * Headless implementation of Confirm that returns sensible defaults instead + * of throwing. Dialogs are logged to stderr so the prompts are visible in + * service logs, and the default/conservative action is taken automatically. + */ +export declare class HeadlessConfirm implements Confirm { + askYesNo(message: string): Promise<"yes" | "no">; + askString(title: string, key: string, placeholder: string, isPassword?: boolean): Promise; + askYesNoDialog(message: string, opt: { + title?: string; + defaultOption?: "Yes" | "No"; + timeout?: number; + }): Promise<"yes" | "no">; + askSelectString(message: string, items: string[]): Promise; + askSelectStringDialogue(message: string, buttons: T, opt: { + title?: string; + defaultAction: T[number]; + timeout?: number; + }): Promise; + askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void): void; + confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>; +} +export declare class HeadlessAPIService extends InjectableAPIService { + private _confirmInstance; + private _systemVaultName; + constructor(context: T); + get confirm(): Confirm; + showWindow(type: string): Promise; + getCustomFetchHandler(): FetchHttpHandler; + isMobile(): boolean; + getAppID(): string; + getAppVersion(): string; + getPluginVersion(): string; + getPlatform(): string; + getCrypto(): Crypto; + addCommand(command: TCommand): TCommand; + addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement; + registerWindow(type: string, factory: (leaf: any) => any): void; + registerProtocolHandler(action: string, handler: (params: Record) => any): void; + addStatusBarItem(): HTMLElement | undefined; + private toSafeKeyPart; + private hash32; + private deriveSystemVaultName; + getSystemVaultName(): string; + get isOnline(): boolean; + nativeFetch(req: string | Request, opts?: RequestInit): Promise; +} diff --git a/_types/lib/src/services/implements/headless/HeadlessDatabaseService.d.ts b/_types/lib/src/services/implements/headless/HeadlessDatabaseService.d.ts new file mode 100644 index 0000000..a2d3fec --- /dev/null +++ b/_types/lib/src/services/implements/headless/HeadlessDatabaseService.d.ts @@ -0,0 +1,7 @@ +import { KeyValueDBService } from "../../base/KeyValueDBService"; +import type { ServiceContext } from "../../base/ServiceBase"; +import { DatabaseService } from "@lib/services/base/DatabaseService.ts"; +export declare class HeadlessDatabaseService extends DatabaseService { +} +export declare class HeadlessKeyValueDBService extends KeyValueDBService { +} diff --git a/_types/lib/src/services/implements/injectable/InjectableAPIService.d.ts b/_types/lib/src/services/implements/injectable/InjectableAPIService.d.ts new file mode 100644 index 0000000..aab5d50 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableAPIService.d.ts @@ -0,0 +1,7 @@ +import { APIService } from "@lib/services/base/APIService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare abstract class InjectableAPIService extends APIService { + addLog: import("@lib/services/lib/HandlerUtils").HandlerFunction<(message: unknown, level: import("octagonal-wheels/common/logger").LOG_LEVEL, key?: string) => void, any>; + getPlatform(): string; + getCrypto(): Crypto; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableAppLifecycleService.d.ts b/_types/lib/src/services/implements/injectable/InjectableAppLifecycleService.d.ts new file mode 100644 index 0000000..b7ee414 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableAppLifecycleService.d.ts @@ -0,0 +1,11 @@ +import { AppLifecycleService } from "@lib/services/base/AppLifecycleService"; +import type { IAppLifecycleService } from "@lib/services/base/IService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare abstract class AppLifecycleServiceBase extends AppLifecycleService { + askRestart: import("@lib/services/lib/HandlerUtils").HandlerFunction<(message?: string) => void, any>; + scheduleRestart: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => void, any>; + isReloadingScheduled: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => boolean, any>; +} +export declare abstract class InjectableAppLifecycleService extends AppLifecycleServiceBase implements IAppLifecycleService { + performRestart: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => void, any>; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableConflictService.d.ts b/_types/lib/src/services/implements/injectable/InjectableConflictService.d.ts new file mode 100644 index 0000000..2f58f92 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableConflictService.d.ts @@ -0,0 +1,11 @@ +import { ConflictService } from "@lib/services/base/ConflictService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class InjectableConflictService extends ConflictService { + queueCheckForIfOpen: import("@lib/services/lib/HandlerUtils").HandlerFunction<(path: import("../../../common/settingConstants").FilePathWithPrefix) => Promise, any>; + queueCheckFor: import("@lib/services/lib/HandlerUtils").HandlerFunction<(path: import("../../../common/settingConstants").FilePathWithPrefix) => Promise, any>; + ensureAllProcessed: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => Promise, any>; + resolveByDeletingRevision: import("@lib/services/lib/HandlerUtils").HandlerFunction<(path: import("../../../common/settingConstants").FilePathWithPrefix, deleteRevision: string, title: string) => Promise, any>; + resolve: import("@lib/services/lib/HandlerUtils").HandlerFunction<(filename: import("../../../common/settingConstants").FilePathWithPrefix) => Promise, any>; + resolveByNewest: import("@lib/services/lib/HandlerUtils").HandlerFunction<(filename: import("../../../common/settingConstants").FilePathWithPrefix) => Promise, any>; + resolveAllConflictedFilesByNewerOnes: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => Promise, any>; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableDatabaseEventService.d.ts b/_types/lib/src/services/implements/injectable/InjectableDatabaseEventService.d.ts new file mode 100644 index 0000000..8f4df0b --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableDatabaseEventService.d.ts @@ -0,0 +1,4 @@ +import { DatabaseEventService } from "@lib/services/base/DatabaseEventService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class InjectableDatabaseEventService extends DatabaseEventService { +} diff --git a/_types/lib/src/services/implements/injectable/InjectableFileProcessingService.d.ts b/_types/lib/src/services/implements/injectable/InjectableFileProcessingService.d.ts new file mode 100644 index 0000000..66fef69 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableFileProcessingService.d.ts @@ -0,0 +1,4 @@ +import { FileProcessingService } from "@lib/services/base/FileProcessingService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class InjectableFileProcessingService extends FileProcessingService { +} diff --git a/_types/lib/src/services/implements/injectable/InjectablePathService.d.ts b/_types/lib/src/services/implements/injectable/InjectablePathService.d.ts new file mode 100644 index 0000000..abc7291 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectablePathService.d.ts @@ -0,0 +1,13 @@ +import type { UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { AnyEntry, FilePathWithPrefix } from "@lib/common/models/db.type"; +import { PathService } from "@lib/services/base/PathService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { BASE_IS_NEW, EVEN, TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols"; +export declare function compareFileFreshnessGeneric(baseFile: UXFileInfoStub | AnyEntry | undefined, checkTarget: UXFileInfo | AnyEntry | undefined): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; +export declare class PathServiceCompat extends PathService { + markChangesAreSame(old: UXFileInfo | AnyEntry | FilePathWithPrefix, newMtime: number, oldMtime: number): boolean | undefined; + unmarkChanges(file: AnyEntry | FilePathWithPrefix | UXFileInfoStub): void; + compareFileFreshness(baseFile: UXFileInfoStub | AnyEntry | undefined, checkTarget: UXFileInfo | AnyEntry | undefined): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; + isMarkedAsSameChanges(file: UXFileInfoStub | AnyEntry | FilePathWithPrefix, mtimes: number[]): undefined | typeof EVEN; + normalizePath(path: string): string; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableRemoteService.d.ts b/_types/lib/src/services/implements/injectable/InjectableRemoteService.d.ts new file mode 100644 index 0000000..44c6593 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableRemoteService.d.ts @@ -0,0 +1,4 @@ +import { RemoteService } from "@lib/services/base/RemoteService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class InjectableRemoteService extends RemoteService { +} diff --git a/_types/lib/src/services/implements/injectable/InjectableReplicationService.d.ts b/_types/lib/src/services/implements/injectable/InjectableReplicationService.d.ts new file mode 100644 index 0000000..85759a8 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableReplicationService.d.ts @@ -0,0 +1,4 @@ +import { ReplicationService } from "@lib/services/base/ReplicationService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class InjectableReplicationService extends ReplicationService { +} diff --git a/_types/lib/src/services/implements/injectable/InjectableReplicatorService.d.ts b/_types/lib/src/services/implements/injectable/InjectableReplicatorService.d.ts new file mode 100644 index 0000000..38d6f8a --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableReplicatorService.d.ts @@ -0,0 +1,4 @@ +import { ReplicatorService } from "@lib/services/base/ReplicatorService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare class InjectableReplicatorService extends ReplicatorService { +} diff --git a/_types/lib/src/services/implements/injectable/InjectableServiceHub.d.ts b/_types/lib/src/services/implements/injectable/InjectableServiceHub.d.ts new file mode 100644 index 0000000..93e09fb --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableServiceHub.d.ts @@ -0,0 +1,71 @@ +import type { ConfigService } from "@lib/services/base/ConfigService"; +import { ControlService } from "@lib/services/base/ControlService"; +import type { KeyValueDBService } from "@lib/services/base/KeyValueDBService"; +import { PathService } from "@lib/services/base/PathService"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import type { SettingService } from "@lib/services/base/SettingService"; +import { ServiceHub } from "@lib/services/ServiceHub"; +import type { UIService } from "@lib/services/implements/base/UIService"; +import { InjectableAPIService } from "./InjectableAPIService"; +import { type AppLifecycleServiceBase } from "./InjectableAppLifecycleService"; +import { InjectableConflictService } from "./InjectableConflictService"; +import { InjectableDatabaseEventService } from "./InjectableDatabaseEventService"; +import { InjectableFileProcessingService } from "./InjectableFileProcessingService"; +import { InjectableRemoteService } from "./InjectableRemoteService"; +import { InjectableReplicationService } from "./InjectableReplicationService"; +import { InjectableReplicatorService } from "./InjectableReplicatorService"; +import type { InjectableServiceInstances } from "./InjectableServices"; +import { InjectableTestService } from "./InjectableTestService"; +import { InjectableTweakValueService } from "./InjectableTweakValueService"; +import { InjectableVaultService } from "./InjectableVaultService"; +import type { DatabaseService } from "@lib/services/base/DatabaseService.ts"; +export declare class InjectableServiceHub extends ServiceHub { + protected readonly _api: InjectableAPIService; + protected readonly _path: PathService; + protected readonly _database: DatabaseService; + protected readonly _databaseEvents: InjectableDatabaseEventService; + protected readonly _replicator: InjectableReplicatorService; + protected readonly _fileProcessing: InjectableFileProcessingService; + protected readonly _replication: InjectableReplicationService; + protected readonly _remote: InjectableRemoteService; + protected readonly _conflict: InjectableConflictService; + protected readonly _appLifecycle: AppLifecycleServiceBase; + protected readonly _setting: SettingService; + protected readonly _tweakValue: InjectableTweakValueService; + protected readonly _vault: InjectableVaultService; + protected readonly _test: InjectableTestService; + protected readonly _ui: UIService; + protected readonly _config: ConfigService; + protected readonly _keyValueDB: KeyValueDBService; + protected readonly _control: ControlService; + get API(): InjectableAPIService; + get path(): PathService; + get database(): DatabaseService; + get databaseEvents(): InjectableDatabaseEventService; + get replicator(): InjectableReplicatorService; + get fileProcessing(): InjectableFileProcessingService; + get replication(): InjectableReplicationService; + get remote(): InjectableRemoteService; + get conflict(): InjectableConflictService; + get appLifecycle(): AppLifecycleServiceBase; + get setting(): SettingService; + get tweakValue(): InjectableTweakValueService; + get vault(): InjectableVaultService; + get test(): InjectableTestService; + get control(): ControlService; + get keyValueDB(): KeyValueDBService; + get UI(): UIService; + get config(): ConfigService; + constructor(context: T, services: InjectableServiceInstances & { + setting: SettingService; + appLifecycle: AppLifecycleServiceBase; + path: PathService; + API: InjectableAPIService; + ui: UIService; + config: ConfigService; + database: DatabaseService; + vault: InjectableVaultService; + keyValueDB: KeyValueDBService; + replicator: InjectableReplicatorService; + }); +} diff --git a/_types/lib/src/services/implements/injectable/InjectableServices.d.ts b/_types/lib/src/services/implements/injectable/InjectableServices.d.ts new file mode 100644 index 0000000..ab41301 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableServices.d.ts @@ -0,0 +1,36 @@ +import { type ServiceInstances } from "@lib/services/ServiceHub.ts"; +import type { UIService } from "@lib/services/implements/base/UIService.ts"; +import type { ConfigService } from "@lib/services/base/ConfigService.ts"; +import type { ServiceContext } from "@lib/services/base/ServiceBase.ts"; +import type { InjectableAPIService } from "./InjectableAPIService"; +import type { InjectableDatabaseEventService } from "./InjectableDatabaseEventService"; +import type { InjectableReplicatorService } from "./InjectableReplicatorService"; +import type { InjectableFileProcessingService } from "./InjectableFileProcessingService"; +import type { InjectableReplicationService } from "./InjectableReplicationService"; +import type { InjectableRemoteService } from "./InjectableRemoteService"; +import type { InjectableConflictService } from "./InjectableConflictService"; +import type { AppLifecycleServiceBase } from "./InjectableAppLifecycleService"; +import type { InjectableTweakValueService } from "./InjectableTweakValueService"; +import type { InjectableVaultService } from "./InjectableVaultService"; +import type { InjectableTestService } from "./InjectableTestService"; +import type { PathService } from "@lib/services/base/PathService"; +import type { DatabaseService } from "@lib/services/base/DatabaseService.ts"; +import type { SettingService } from "@lib/services/base/SettingService"; +export type InjectableServiceInstances = ServiceInstances & { + API?: InjectableAPIService; + path?: PathService; + database?: DatabaseService; + databaseEvents?: InjectableDatabaseEventService; + replicator?: InjectableReplicatorService; + fileProcessing?: InjectableFileProcessingService; + replication?: InjectableReplicationService; + remote?: InjectableRemoteService; + conflict?: InjectableConflictService; + appLifecycle?: AppLifecycleServiceBase; + setting?: SettingService; + tweakValue?: InjectableTweakValueService; + vault?: InjectableVaultService; + test?: InjectableTestService; + ui?: UIService; + config?: ConfigService; +}; diff --git a/_types/lib/src/services/implements/injectable/InjectableSettingService.d.ts b/_types/lib/src/services/implements/injectable/InjectableSettingService.d.ts new file mode 100644 index 0000000..f939b16 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableSettingService.d.ts @@ -0,0 +1,11 @@ +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { SettingService, type SettingServiceDependencies } from "@lib/services/base/SettingService"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +export declare class InjectableSettingService extends SettingService { + constructor(context: T, dependencies: SettingServiceDependencies); + protected setItem(key: string, value: string): void; + protected getItem(key: string): string; + protected deleteItem(key: string): void; + saveData: import("@lib/services/lib/HandlerUtils").HandlerFunction<(data: ObsidianLiveSyncSettings) => Promise, any>; + loadData: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => Promise, any>; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableTestService.d.ts b/_types/lib/src/services/implements/injectable/InjectableTestService.d.ts new file mode 100644 index 0000000..dfc2a71 --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableTestService.d.ts @@ -0,0 +1,5 @@ +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { TestService } from "@lib/services/base/TestService"; +export declare class InjectableTestService extends TestService { + addTestResult: import("@lib/services/lib/HandlerUtils").HandlerFunction<(name: string, key: string, result: boolean, summary?: string, message?: string) => void, any>; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableTweakValueService.d.ts b/_types/lib/src/services/implements/injectable/InjectableTweakValueService.d.ts new file mode 100644 index 0000000..3eb55da --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableTweakValueService.d.ts @@ -0,0 +1,15 @@ +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { TweakValueService } from "@lib/services/base/TweakValueService"; +export declare class InjectableTweakValueService extends TweakValueService { + fetchRemotePreferred: import("@lib/services/lib/HandlerUtils").HandlerFunction<(trialSetting: import("../../../common/types").RemoteDBSettings) => Promise, any>; + checkAndAskResolvingMismatched: import("@lib/services/lib/HandlerUtils").HandlerFunction<(preferred: Partial) => Promise<[import("../../../common/types").TweakValues | boolean, boolean]>, any>; + askResolvingMismatched: import("@lib/services/lib/HandlerUtils").HandlerFunction<(preferredSource: import("../../../common/types").TweakValues) => Promise<"OK" | "CHECKAGAIN" | "IGNORE">, any>; + checkAndAskUseRemoteConfiguration: import("@lib/services/lib/HandlerUtils").HandlerFunction<(settings: import("../../../common/types").RemoteDBSettings) => Promise<{ + result: false | import("../../../common/types").TweakValues; + requireFetch: boolean; + }>, any>; + askUseRemoteConfiguration: import("@lib/services/lib/HandlerUtils").HandlerFunction<(trialSetting: import("../../../common/types").RemoteDBSettings, preferred: import("../../../common/types").TweakValues) => Promise<{ + result: false | import("../../../common/types").TweakValues; + requireFetch: boolean; + }>, any>; +} diff --git a/_types/lib/src/services/implements/injectable/InjectableVaultService.d.ts b/_types/lib/src/services/implements/injectable/InjectableVaultService.d.ts new file mode 100644 index 0000000..120bdba --- /dev/null +++ b/_types/lib/src/services/implements/injectable/InjectableVaultService.d.ts @@ -0,0 +1,9 @@ +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +import { VaultService } from "@lib/services/base/VaultService"; +export declare abstract class InjectableVaultService extends VaultService { +} +export declare class InjectableVaultServiceCompat extends InjectableVaultService { + isStorageInsensitive: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => boolean, any>; + getActiveFilePath: import("@lib/services/lib/HandlerUtils").HandlerFunction<() => import("../../../common/settingConstants").FilePath | undefined, any>; + isValidPath(path: string): boolean; +} diff --git a/_types/lib/src/services/implements/obsidian/ObsidianServiceContext.d.ts b/_types/lib/src/services/implements/obsidian/ObsidianServiceContext.d.ts new file mode 100644 index 0000000..590d2fe --- /dev/null +++ b/_types/lib/src/services/implements/obsidian/ObsidianServiceContext.d.ts @@ -0,0 +1,9 @@ +import { ServiceContext } from "@lib/services/base/ServiceBase"; +import type ObsidianLiveSyncPlugin from "@/main"; +import type { App, Plugin } from "@/deps"; +export declare class ObsidianServiceContext extends ServiceContext { + app: App; + plugin: Plugin; + liveSyncPlugin: ObsidianLiveSyncPlugin; + constructor(app: App, plugin: Plugin, liveSyncPlugin: ObsidianLiveSyncPlugin); +} diff --git a/_types/lib/src/services/lib/HandlerUtils.d.ts b/_types/lib/src/services/lib/HandlerUtils.d.ts new file mode 100644 index 0000000..c293706 --- /dev/null +++ b/_types/lib/src/services/lib/HandlerUtils.d.ts @@ -0,0 +1,374 @@ +/** + * A function type that can be used as a handler. + */ +type HandlerFunc = (...args: TArg) => TResult | Promise; +/** + * A function type that returns a boolean or a Promise of boolean. + */ +type BooleanHandlerFunc = (...args: TArg) => U | Promise; +/** + * An interface for invokable handlers that can add and remove handler functions. + */ +export interface InvokableHandler { + /** + * Invokes the handler with the provided arguments. + * @param args The arguments to pass to the handler. + * @returns A Promise that resolves to the result of the handler. + */ + invoke(...args: T): Promise; +} +/** + * An interface for invokable boolean handlers that can add and remove handler functions. + */ +type InvokableBooleanHandler = InvokableHandler; +/** + * A function type that can be used to unregister a handler. + */ +export type UnregisterFunction = () => void; +/** + * An interface for binder handlers that can assign a single handler function. + */ +export interface BinderHandler { + assign(callback: HandlerFunc, override?: boolean): UnregisterFunction; +} +/** + * An interface for multi-binder handlers that can add and remove handler functions. + */ +export interface MultiRegisterHandler { + /** + * Adds a handler function. + * Note: The same function only added once. + * If you want to prevent duplication, please remove the existing handler before adding it again. + * @param callback The handler function to add. + * @returns A function to remove the added handler. + */ + addHandler(callback: BooleanHandlerFunc): UnregisterFunction; + /** + * Removes a handler function. + * @param callback The handler function to remove. + */ + removeHandler(callback: BooleanHandlerFunc): void; + use(callback: BooleanHandlerFunc): UnregisterFunction; +} +/** + * An interface for dispatch handlers that can dispatch events to multiple handlers. + */ +export interface DispatcherHandler { + dispatch(...args: T): Promise<(Awaited | Error)[]>; +} +/** + * An interface for dispatch handlers that can add and remove handler functions. + */ +export interface DispatchHandler extends DispatcherHandler, MultiRegisterHandler { +} +/** + * A binder that allows assigning and invoking a single handler function. + */ +export declare class Binder> implements BinderHandler, ReturnType>, InvokableHandler, ReturnType> { + private _name; + /** + * Creates a new Binder instance. + * @param name The name of the handler. + * @param initialCallback An optional initial callback function to assign. + */ + constructor(name: string, initialCallback?: T); + private _callback; + /** + * Assigns a new handler function. + * @param callback The new handler function to assign. + */ + assign(callback: T, override?: boolean): () => void; + /** + * Invokes the assigned handler function with the provided arguments. + * @param args The arguments to pass to the handler function. + * @returns The result of the handler function. + */ + invoke(...args: Parameters): ReturnType; +} +/** + * A binder that allows assigning and invoking a single handler function asynchronously. + * The invocation will wait until a handler is assigned. + */ +export declare class LazyBinder> implements BinderHandler, ReturnType>, InvokableHandler, Promise>>> { + private _name; + private _callbackPromise; + private _callback; + /** + * Creates a new LazyBinder instance. + * @param name The name of the handler. + * @param initialCallback An optional initial callback function to assign. + */ + constructor(name: string, initialCallback?: T); + assign(callback: T, override?: boolean): () => void; + /** + * Invokes the assigned handler function with the provided arguments. + * @param args The arguments to pass to the handler function. + * @returns The result of the handler function. + */ + invoke(...args: Parameters): Promise>>; +} +/** + * A multi-binder that allows adding and removing multiple handler functions. + */ +export declare class MultiBinder> implements MultiRegisterHandler, ReturnType> { + protected _name: string; + /** + * Creates a new MultiBinder instance. + * @param name The name of the handler. + */ + constructor(name: string); + protected _callbackMap: Map; + protected _isCallbackDirty: boolean; + protected _maxUsedPriority: number; + /** + * Adds a handler function. + * Note: The same function is only added once. + * @param callback The handler function to add. + * @param priority The priority of the handler, Do not use floating numbers to prevent confusion. + * @returns A function to unregister the added handler. + * + */ + addHandler(callback: T, priority?: number, allowSwap?: boolean): UnregisterFunction; + /** + * Removes a handler function. + * @param callback The handler function to remove. + */ + removeHandler(callback: T): void; + /** + * Adds a handler function (alias of addHandler, but more semantic). + * @param callback + * @returns + */ + use(callback: T, priority?: number): UnregisterFunction; + _sortedCallbacks: T[]; + protected get _callbacks(): T[]; +} +/** + * A dispatcher that invokes all added handler functions sequentially and collects their results. + * */ +export declare class Dispatch extends MultiBinder> implements DispatcherHandler { + /** + * Dispatches the event to all registered handlers sequentially. + * @param args The arguments to pass to the handlers. + * @returns An array of results or errors from each handler. + */ + dispatch(...args: T): Promise<(Awaited | Error)[]>; +} +/** + * A dispatcher that invokes all added handler functions in parallel and collects their results. + */ +export declare class DispatchParallel extends MultiBinder> implements DispatcherHandler { + /** + * Dispatches the event to all registered handlers in parallel. + * @param args The arguments to pass to the handlers. + * @returns An array of results or errors from each handler. + */ + dispatch(...args: T): Promise<(Awaited | Error)[]>; +} +/** + * A base class for boolean handlers that can add and remove handler functions. + */ +export declare abstract class BooleanHandlerBase extends MultiBinder> implements InvokableBooleanHandler { + abstract invoke(...args: T): Promise; +} +/** + * A handler that invokes all added handler functions sequentially until one returns false. + */ +export declare class AllHandler extends BooleanHandlerBase { + /** + * Invoke all handlers sequentially until one returns false. + * @param args The arguments to pass to the handlers. + * @returns A Promise that resolves to true if all handlers return true, otherwise false. + */ + invoke(...args: T): Promise; +} +/** + * A handler that invokes all added handler functions in parallel and returns true only if all return true. + */ +export declare class ParallelAllHandler extends BooleanHandlerBase { + /** + * Invoke all handlers in parallel + * @param args The arguments to pass to the handlers. + * @returns True if all handlers return true, otherwise false. + */ + invoke(...args: T): Promise; +} +/** + * A handler that invokes all added handler functions sequentially until one returns true. + */ +export declare class AnySuccessHandler extends BooleanHandlerBase { + /** + * Invokes handlers sequentially until one returns true. + * @param args The arguments to pass to the handlers. + * @returns True if any handler returns true, otherwise false. + */ + invoke(...args: T): Promise; +} +/** + * A handler that invokes all added handler functions sequentially until one returns a non-falsy value. + */ +export declare class FirstResultHandler extends MultiBinder> { + /** + * Invokes handlers sequentially until one returns a non-falsy value. + * @param args The arguments to pass to the handlers. + * @returns The first non-falsy result from the handlers, or false if none found. + */ + invoke(...args: T): Promise; +} +/** + * A function type that can be used as a handler with assignable functionality. + */ +export interface HandlerFunction U | Promise, U = any> { + /** + * Invokes the handler function with the provided arguments. + */ + (...args: Parameters): ReturnType; + /** + * Assigns a new handler function. + * @param callback The new handler function to assign. + * @param override Whether to override the existing handler if one is already assigned. + * @returns A function to unregister the assigned handler. + */ + setHandler: (callback: TFunc, override?: boolean) => void; +} +/** + * A function type that can be used as a handler with assignable functionality. + */ +export interface LazyHandlerFunction U | Promise, U = any> { + /** + * Invokes the handler function with the provided arguments. + */ + (...args: Parameters): Promise>>; + /** + * Assigns a new handler function. + * @param callback The new handler function to assign. + * @param override Whether to override the existing handler if one is already assigned. + * @returns A function to unregister the assigned handler. + */ + setHandler: (callback: TFunc, override?: boolean) => void; +} +/** + * A function type that can be used as a multiple handler with add/remove functionality. + */ +export interface MultipleHandlerFunction U | Promise, U = any> { + /** + * Invokes the handler function with the provided arguments. + */ + (...args: Parameters): ReturnType; + /** + * Adds a handler function. + * @param callback The handler function to add. + * @returns A function to remove the added handler. + */ + addHandler: (callback: TFunc) => () => void; + /** + * Removes a handler function. + * @param callback The handler function to remove. + * @returns + */ + removeHandler: (callback: TFunc) => void; +} +/** + * A function type that can be used as a value-collecting handler with add/remove functionality. + */ +export type CollectorFunction U | Promise, U = any> = (...args: Parameters) => Promise>; +/** + * A Handler function type that can have multiple handlers added or removed, and collects their results into an array. + */ +export interface CollectiveHandlerFunction U[] | Promise, U = any> { + /** + * Invokes the handler function with the provided arguments. + */ + (...args: Parameters): ReturnType; + /** + * Adds a handler function. + * @param callback The handler function to add. + * @returns A function to remove the added handler. + */ + addHandler: (callback: CollectorFunction) => () => void; + /** + * Removes a handler function. + * @param callback The handler function to remove. + * @returns + */ + removeHandler: (callback: CollectorFunction) => void; +} +export interface BooleanMultipleHandlerFunction boolean | Promise> { + /** + * Invokes the handler function with the provided arguments. + */ + (...args: Parameters): ReturnType; + /** + * Adds a handler function. + * @param callback The handler function to add. + * @returns A function to remove the added handler. + */ + addHandler: (callback: TFunc, priority?: number) => () => void; + /** + * Removes a handler function. + * @param callback The handler function to remove. + * @returns + */ + removeHandler: (callback: TFunc) => void; +} +export interface MultiBinderInstance extends InvokableHandler, MultiRegisterHandler { +} +export interface BooleanMultiBinderInstance extends InvokableBooleanHandler, MultiRegisterHandler { +} +export declare function allFunction Promise>(name?: string): BooleanMultipleHandlerFunction; +export declare function bailFirstFailureFunction Promise>(name?: string): BooleanMultipleHandlerFunction; +export declare function allParallelFunction Promise>(name?: string): BooleanMultipleHandlerFunction; +export declare function anySuccessFunction Promise>(name?: string): BooleanMultipleHandlerFunction; +export declare function firstResultFunction Promise>(name?: string): MultipleHandlerFunction; +export declare function dispatchParallelFunction Promise>(name?: string): CollectiveHandlerFunction; +export declare function bindableFunction any>(name?: string): HandlerFunction; +export declare function lazyBindableFunction any>(name?: string): LazyHandlerFunction; +type FunctionKeys = Extract<{ + [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; +}[keyof T], string>; +export declare function handlers(): { + /** + * Create a handler that invokes all added handler functions sequentially until one returns false. + * @param name + * @returns + */ + all>(name: K): BooleanMultipleHandlerFunction Promise>>; + /** + * Create a handler that invokes all added handler functions in parallel and returns true only if all return true. + * @param name + * @returns + */ + allParallel>(name: K): BooleanMultipleHandlerFunction Promise>>; + /** + * Create a handler that invokes all added handler functions sequentially until one returns false. + * @param name + * @returns + */ + bailFirstFailure>(name: K): BooleanMultipleHandlerFunction Promise>>; + /** + * Create a handler that invokes all added handler functions sequentially until one returns true. + * @param name + * @returns + */ + anySuccess>(name: K): BooleanMultipleHandlerFunction Promise>>; + /** + * Create a handler that invokes all added handler functions sequentially until one returns a non-falsy value. + * @param name + * @returns + */ + firstResult>(name: K): MultipleHandlerFunction Promise>>; + /** + * Create a handler that invokes all added handler functions in parallel. + * @param name + * @returns + */ + dispatchParallel>(name: K): CollectiveHandlerFunction Promise>>; + /** + * Create a binder handler that can assign a single handler function. + * @param name + * @returns + */ + binder>(name: K): HandlerFunction any>>; + lazyBinder>(name: K): LazyHandlerFunction any>>; +}; +export {}; diff --git a/_types/lib/src/services/lib/MiddlewareUtils.d.ts b/_types/lib/src/services/lib/MiddlewareUtils.d.ts new file mode 100644 index 0000000..9d97f1f --- /dev/null +++ b/_types/lib/src/services/lib/MiddlewareUtils.d.ts @@ -0,0 +1,29 @@ +export interface MiddlewareContext { + next: () => Promise; + state: Record; +} +type TargetFunc = (...args: TArgs) => Promise; +type MiddlewareFunc = (ctx: MiddlewareContext, ...args: TArgs) => Promise; +export declare class MiddlewareManager { + private middlewares; + private _indexCounter; + private _isMiddlewareDirty; + use(priority: number, func: MiddlewareFunc): () => void; + setFinal(func: TargetFunc): void; + private sortMiddlewares; + protected onStepRunOut: (...args: TArgs) => Promise; + private composed; + private compose; + invoke(...args: TArgs): Promise; +} +type FunctionKeys = { + [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; +}[keyof T]; +export declare function middlewares any>>(): { + useMiddleware>(key: K): { + use: (priority: number, func: MiddlewareFunc, Awaited>>) => () => void; + invoke: (...args: Parameters) => Promise>>; + setFinal: (func: TargetFunc, Awaited>>) => void; + }; +}; +export {}; diff --git a/_types/lib/src/services/lib/logUtils.d.ts b/_types/lib/src/services/lib/logUtils.d.ts new file mode 100644 index 0000000..22d38b9 --- /dev/null +++ b/_types/lib/src/services/lib/logUtils.d.ts @@ -0,0 +1,13 @@ +import { type LOG_LEVEL } from "octagonal-wheels/common/logger"; +import type { IAPIService } from "@lib/services/base/IService"; +export declare const MARK_LOG_SEPARATOR = "\u200A"; +export declare const MARK_LOG_NETWORK_ERROR = "\u200B"; +/** + * Creates a log function that prefixes messages with the service name and uses the provided APIService's addLog method if available. + * If APIService is not provided, it falls back to using the global Logger function. + * @param serviceName The name of the service to prefix log messages with. + * @param APIService An optional APIService instance to use for logging. + * @returns A log function that can be used to log messages with the specified service name and APIService. + */ +export declare function createInstanceLogFunction(serviceName: string, APIService?: IAPIService): (msg: unknown, level?: LOG_LEVEL, key?: string) => void; +export type LogFunction = ReturnType; diff --git a/_types/lib/src/string_and_binary/chunks.d.ts b/_types/lib/src/string_and_binary/chunks.d.ts new file mode 100644 index 0000000..fdf2628 --- /dev/null +++ b/_types/lib/src/string_and_binary/chunks.d.ts @@ -0,0 +1,10 @@ +export declare function splitPiecesTextV2(dataSrc: string | string[], pieceSize: number, minimumChunkSize: number): () => Generator; +export declare function binaryTextSplit(data: string, pieceSize: number, minimumChunkSize: number): () => Generator; +export declare function splitPiecesText(dataSrc: string | string[], pieceSize: number, plainSplit: boolean, minimumChunkSize: number, useSegmenter: boolean): () => Generator; +export declare function splitPiecesTextV1(dataSrc: string | string[], pieceSize: number, plainSplit: boolean, minimumChunkSize: number): () => Generator; +export declare function collectGenAll(strGen: AsyncGenerator | Generator): Promise; +export declare function concatGeneratedAll(strGen: AsyncGenerator | Generator): Promise; +export declare function splitPieces2V2(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): Promise<(() => Generator) | (() => AsyncGenerator)>; +export declare function splitPieces2(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): Promise<(() => Generator) | (() => AsyncGenerator)>; +export declare function splitPiecesRabinKarp(dataSrc: Blob, absoluteMaxPieceSize: number, doPlainSplit: boolean, minimumChunkSize: number, _filename?: string, _useSegmenter?: boolean): Promise<() => AsyncGenerator>; +export declare function splitPiecesRabinKarpOld(dataSrc: Blob, absoluteMaxPieceSize: number, doPlainSplit: boolean, minimumChunkSize: number, _filename?: string, _useSegmenter?: boolean): Promise<() => AsyncGenerator>; diff --git a/_types/lib/src/string_and_binary/convert.d.ts b/_types/lib/src/string_and_binary/convert.d.ts new file mode 100644 index 0000000..ec0296a --- /dev/null +++ b/_types/lib/src/string_and_binary/convert.d.ts @@ -0,0 +1,8 @@ +import { arrayBufferToBase64, base64ToArrayBuffer, base64ToArrayBufferInternalBrowser, readString, writeString, tryConvertBase64ToArrayBuffer } from "octagonal-wheels/binary"; +export { arrayBufferToBase64, base64ToArrayBuffer, base64ToArrayBufferInternalBrowser, readString, writeString, tryConvertBase64ToArrayBuffer, }; +export declare function arrayBufferToBase64Single(buffer: Uint8Array | ArrayBuffer): Promise; +export { uint8ArrayToHexString, hexStringToUint8Array } from "octagonal-wheels/binary/hex"; +export { encodeBinaryEach, decodeToArrayBuffer } from "octagonal-wheels/binary/encodedUTF16"; +export { decodeBinary, encodeBinary } from "octagonal-wheels/binary"; +export { escapeStringToHTML } from "octagonal-wheels/string"; +export declare function versionNumberString2Number(version: string): number; diff --git a/_types/lib/src/string_and_binary/hash.d.ts b/_types/lib/src/string_and_binary/hash.d.ts new file mode 100644 index 0000000..efc3fa2 --- /dev/null +++ b/_types/lib/src/string_and_binary/hash.d.ts @@ -0,0 +1,2 @@ +export * from "octagonal-wheels/hash/xxhash.js"; +export type * from "octagonal-wheels/hash/xxhash.js"; diff --git a/_types/lib/src/string_and_binary/path.d.ts b/_types/lib/src/string_and_binary/path.d.ts new file mode 100644 index 0000000..b01a380 --- /dev/null +++ b/_types/lib/src/string_and_binary/path.d.ts @@ -0,0 +1,35 @@ +import type { AnyEntry, DocumentID, EntryHasPath, FilePath, FilePathWithPrefix } from "@lib/common/models/db.type"; +export declare function isValidFilenameInWidows(filename: string): boolean; +export declare function isValidFilenameInDarwin(filename: string): boolean; +export declare function isValidFilenameInLinux(filename: string): boolean; +export declare function isValidFilenameInAndroid(filename: string): boolean; +export declare function isFilePath(path: FilePath | FilePathWithPrefix): path is FilePath; +export declare function stripAllPrefixes(prefixedPath: FilePathWithPrefix): FilePath; +export declare function addPrefix(path: FilePath | FilePathWithPrefix, prefix: string): FilePathWithPrefix; +export declare function expandFilePathPrefix(path: FilePathWithPrefix | FilePath): [string, FilePathWithPrefix]; +export declare function expandDocumentIDPrefix(id: DocumentID): [string, FilePathWithPrefix]; +export declare function path2id_base(filenameSrc: FilePathWithPrefix | FilePath, obfuscatePassphrase: string | false, caseInsensitive: boolean): Promise; +export declare function id2path_base(id: DocumentID, entry?: EntryHasPath): FilePathWithPrefix; +export declare function getPath(entry: AnyEntry): FilePathWithPrefix; +export declare function getPathWithoutPrefix(entry: AnyEntry): FilePath; +export declare function stripPrefix(prefixedPath: FilePathWithPrefix): FilePath; +export declare function shouldBeIgnored(filename: string): boolean; +export declare function isPlainText(filename: string): boolean; +export declare function shouldSplitAsPlainText(filename: string): boolean; +/** + * returns whether the given path is accepted (not ignored) by the `.gitignore`. + * @param path path of the file which is relative from `.gitignore` file + * @param ignore lines of `.gitignore` + * @returns true when accepted. + * false when not accepted. + * undefined when the path is not mentioned in the `.gitignore` file. + */ +export declare function isAccepted(path: string, ignore: string[]): boolean | undefined; +/** + * Checks whether the path is accepted by all ignored files. + * @param path path of target file + * @param ignoreFiles list of ignore files. i.e. [".gitignore", ".dockerignore"] + * @param getList function to retrieve the file. + * @returns true when accepted. false when should be ignored. + */ +export declare function isAcceptedAll(path: string, ignoreFiles: string[], getList: (path: string) => Promise): Promise; diff --git a/_types/lib/src/system/wakelock.d.ts b/_types/lib/src/system/wakelock.d.ts new file mode 100644 index 0000000..341dce5 --- /dev/null +++ b/_types/lib/src/system/wakelock.d.ts @@ -0,0 +1,6 @@ +/** + * Run callback with screen wake lock held. + * @param callback Callback to run with wake lock held + * @returns Result of callback + */ +export declare function withWakeLock(callback: () => Promise): Promise; diff --git a/_types/lib/src/worker/bg.common.d.ts b/_types/lib/src/worker/bg.common.d.ts new file mode 100644 index 0000000..d835a3b --- /dev/null +++ b/_types/lib/src/worker/bg.common.d.ts @@ -0,0 +1,2 @@ +import type { END_OF_DATA } from "./universalTypes.ts"; +export declare function postBack(key: number, seq: number, data: string | END_OF_DATA): void; diff --git a/_types/lib/src/worker/bg.worker.d.ts b/_types/lib/src/worker/bg.worker.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/_types/lib/src/worker/bg.worker.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/_types/lib/src/worker/bg.worker.encryption.d.ts b/_types/lib/src/worker/bg.worker.encryption.d.ts new file mode 100644 index 0000000..16aecb6 --- /dev/null +++ b/_types/lib/src/worker/bg.worker.encryption.d.ts @@ -0,0 +1,7 @@ +import type { EncryptHKDFArguments } from "./universalTypes.ts"; +import type { EncryptArguments } from "./universalTypes.ts"; +/** + * Processes the encryption of data. + * @param data The data to be encrypted or decrypted. + */ +export declare function processEncryption(data: EncryptArguments | EncryptHKDFArguments): Promise; diff --git a/_types/lib/src/worker/bg.worker.splitting.d.ts b/_types/lib/src/worker/bg.worker.splitting.d.ts new file mode 100644 index 0000000..c468917 --- /dev/null +++ b/_types/lib/src/worker/bg.worker.splitting.d.ts @@ -0,0 +1,6 @@ +import type { SplitArguments } from "./universalTypes.ts"; +/** + * Processes the splitting of data into chunks. + * @param data The data to be split. + */ +export declare function processSplit(data: SplitArguments): Promise; diff --git a/_types/lib/src/worker/bgWorker.d.ts b/_types/lib/src/worker/bgWorker.d.ts new file mode 100644 index 0000000..1cb26f9 --- /dev/null +++ b/_types/lib/src/worker/bgWorker.d.ts @@ -0,0 +1,82 @@ +import type { EncryptArguments, EncryptHKDFArguments, EncryptHKDFProcessItem, EncryptProcessItem, ProcessItem, SplitArguments, SplitProcessItem } from "./universalTypes.ts"; +export type WorkerInstance = { + worker: Worker; + processing: number; + /** Keys of tasks currently dispatched to this worker instance. */ + taskKeys: Set; +}; +export declare function splitPieces2Worker(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): () => AsyncGenerator; +export declare function splitPieces2WorkerV2(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): () => AsyncGenerator; +export declare function splitPieces2WorkerRabinKarp(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): () => AsyncGenerator; +export declare function encryptWorker(input: string, passphrase: string, autoCalculateIterations: boolean): Promise; +export declare function decryptWorker(input: string, passphrase: string, autoCalculateIterations: boolean): Promise; +export declare function encryptHKDFWorker(input: string, passphrase: string, pbkdf2Salt: Uint8Array): Promise; +export declare function decryptHKDFWorker(input: string, passphrase: string, pbkdf2Salt: Uint8Array): Promise; +export declare const tasks: Map; +/** + * Remove a completed (or aborted) task from both the tasks map and its worker's taskKeys set. + */ +export declare function removeTask(key: number): void; +export declare const _internal: { + abortSplitTasks: typeof abortSplitTasks; + handleTaskSplit: typeof handleTaskSplit; + handleTaskEncrypt: typeof handleTaskEncrypt; +}; +export declare function initialiseWorkerModule(): void; +export declare function startWorker(data: Omit): EncryptHKDFProcessItem; +export declare function startWorker(data: Omit): EncryptProcessItem; +export declare function startWorker(data: Omit): SplitProcessItem; +export declare function terminateWorker(): void; +/** + * Offloads encryption to a web worker. + * @param data The data to be encrypted. + * @returns A promise that resolves with the encryption result. + */ +export declare function encryptionOnWorker(data: Omit): Promise; +/** + * Offloads HKDF encryption to a web worker. + * @param data The data to be encrypted. + * @returns A promise that resolves with the encryption result. + */ +export declare function encryptionHKDFOnWorker(data: Omit): Promise; +/** + * Handles the encryption callbacks + * @param process The process item associated with the task. + * @param data The data to be processed. + */ +export declare function handleTaskEncrypt(process: EncryptProcessItem | EncryptHKDFProcessItem, data: { + key: number; + result?: string; + error?: unknown; +}): void; +/** + * Splits data into pieces using a worker. + * @param dataSrc The source data to be split. + * @param pieceSize The size of each piece. + * @param plainSplit Whether to use plain splitting. + * @param minimumChunkSize The minimum size of each chunk. + * @param filename The name of the file being processed. + * @param splitVersion The version of the splitting algorithm to use. + * @param useSegmenter Whether to use a segmenter (only works on splitVersion:2) + * @returns A generator that yields the split pieces. + */ +export declare function _splitPieces2Worker(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename: string | undefined, splitVersion: 1 | 2 | 3, useSegmenter: boolean): () => AsyncGenerator; +/** + * Aborts all in-flight split tasks identified by the given keys. + * Called when the background worker that owned these tasks has crashed, so the streams + * will never receive any more data and must be torn down to unblock callers. + * @param keys The task keys to abort. + * @param error The error to report to each stream. + */ +export declare function abortSplitTasks(keys: number[], error: Error): void; +/** + * Handles the splitting callback from the worker. + * @param process the splitting process item + * @param data the data received from the worker + */ +export declare function handleTaskSplit(process: SplitProcessItem, data: { + key: number; + seq?: number; + result?: string | null; + error?: unknown; +}): void; diff --git a/_types/lib/src/worker/bgWorker.mock.d.ts b/_types/lib/src/worker/bgWorker.mock.d.ts new file mode 100644 index 0000000..5143c7c --- /dev/null +++ b/_types/lib/src/worker/bgWorker.mock.d.ts @@ -0,0 +1,39 @@ +import type { EncryptHKDFProcessItem, EncryptProcessItem, SplitProcessItem, ProcessItem } from "./universalTypes.ts"; +export type SplitArguments = { + key: number; + type: "split"; + dataSrc: Blob; + pieceSize: number; + plainSplit: boolean; + minimumChunkSize: number; + filename?: string; + useV2: boolean; + useSegmenter: boolean; +}; +export type EncryptArguments = { + key: number; + type: "encrypt" | "decrypt"; + input: string; + passphrase: string; + autoCalculateIterations: boolean; +}; +export type EncryptHKDFArguments = { + key: number; + type: "encryptHKDF" | "decryptHKDF"; + input: string; + passphrase: string; + pbkdf2Salt: Uint8Array; +}; +export declare function terminateWorker(): void; +export declare function splitPieces2Worker(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): Promise<(() => Generator) | (() => AsyncGenerator)>; +export declare function splitPieces2WorkerV2(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): Promise<(() => Generator) | (() => AsyncGenerator)>; +export declare function splitPieces2WorkerRabinKarp(dataSrc: Blob, pieceSize: number, plainSplit: boolean, minimumChunkSize: number, filename?: string, useSegmenter?: boolean): () => AsyncGenerator; +export declare function encryptWorker(input: string, passphrase: string, autoCalculateIterations: boolean): Promise; +export declare function decryptWorker(input: string, passphrase: string, autoCalculateIterations: boolean): Promise; +export declare function encryptHKDFWorker(input: string, passphrase: string, pbkdf2Salt: Uint8Array): Promise; +export declare function decryptHKDFWorker(input: string, passphrase: string, pbkdf2Salt: Uint8Array): Promise; +export declare function startWorker(data: Omit): EncryptHKDFProcessItem; +export declare function startWorker(data: Omit): EncryptProcessItem; +export declare function startWorker(data: Omit): SplitProcessItem; +export declare const tasks: Map; +export declare function initialiseWorkerModule(): void; diff --git a/_types/lib/src/worker/universalTypes.d.ts b/_types/lib/src/worker/universalTypes.d.ts new file mode 100644 index 0000000..e6a1937 --- /dev/null +++ b/_types/lib/src/worker/universalTypes.d.ts @@ -0,0 +1,46 @@ +import type { PromiseWithResolvers } from "octagonal-wheels/promises"; +export type EncryptArguments = { + key: number; + type: "encrypt" | "decrypt"; + input: string; + passphrase: string; + autoCalculateIterations: boolean; +}; +export type EncryptHKDFArguments = { + key: number; + type: "encryptHKDF" | "decryptHKDF"; + input: string; + passphrase: string; + pbkdf2Salt: Uint8Array; +}; +export type SplitArguments = { + key: number; + type: "split"; + dataSrc: Blob; + pieceSize: number; + plainSplit: boolean; + minimumChunkSize: number; + filename?: string; + useSegmenter: boolean; + splitVersion: 1 | 2 | 3; +}; +export type SplitProcessItem = { + key: number; + type: SplitArguments["type"]; + finalize: () => void; +}; +export type EncryptProcessItem = { + key: number; + task: PromiseWithResolvers; + type: EncryptArguments["type"]; + finalize: () => void; +}; +export type EncryptHKDFProcessItem = { + key: number; + task: PromiseWithResolvers; + type: EncryptHKDFArguments["type"]; + finalize: () => void; +}; +export type ProcessItem = SplitProcessItem | EncryptProcessItem | EncryptHKDFProcessItem; +export declare const END_OF_DATA: null; +export type END_OF_DATA = typeof END_OF_DATA; diff --git a/_types/main.d.ts b/_types/main.d.ts new file mode 100644 index 0000000..aa6206e --- /dev/null +++ b/_types/main.d.ts @@ -0,0 +1,20 @@ +import { Plugin, type App, type PluginManifest } from "./deps"; +import { LiveSyncCommands } from "./features/LiveSyncCommands.ts"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext.ts"; +import { LiveSyncBaseCore } from "./LiveSyncBaseCore.ts"; +export type LiveSyncCore = LiveSyncBaseCore; +export default class ObsidianLiveSyncPlugin extends Plugin { + core: LiveSyncCore; + /** + * Initialise service modules. + */ + private initialiseServiceModules; + /** + * @obsolete Use services.setting.saveSettingData instead. Save the settings to the disk. This is usually called after changing the settings in the code, to persist the changes. + */ + saveSettings(): Promise; + constructor(app: App, manifest: PluginManifest); + private _startUp; + onload(): void; + onunload(): undefined; +} diff --git a/_types/managers/ObsidianStorageEventManagerAdapter.d.ts b/_types/managers/ObsidianStorageEventManagerAdapter.d.ts new file mode 100644 index 0000000..2b2b5c1 --- /dev/null +++ b/_types/managers/ObsidianStorageEventManagerAdapter.d.ts @@ -0,0 +1,65 @@ +import { TFile, TFolder } from "@/deps"; +import type { FilePath } from "@lib/common/models/db.type"; +import type { UXFileInfoStub, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { FileEventItem } from "@lib/common/models/fileaccess.type"; +import type { IStorageEventManagerAdapter } from "@lib/managers/adapters"; +import type { IStorageEventTypeGuardAdapter, IStorageEventPersistenceAdapter, IStorageEventWatchAdapter, IStorageEventStatusAdapter, IStorageEventConverterAdapter, IStorageEventWatchHandlers } from "@lib/managers/adapters"; +import type { FileEventItemSentinel } from "@lib/managers/StorageEventManager"; +import type ObsidianLiveSyncPlugin from "@/main"; +import type { LiveSyncCore } from "@/main"; +import type { FileProcessingService } from "@lib/services/base/FileProcessingService"; +/** + * Obsidian-specific type guard adapter + */ +declare class ObsidianTypeGuardAdapter implements IStorageEventTypeGuardAdapter { + isFile(file: unknown): file is TFile; + isFolder(item: unknown): item is TFolder; +} +/** + * Obsidian-specific persistence adapter + */ +declare class ObsidianPersistenceAdapter implements IStorageEventPersistenceAdapter { + private core; + constructor(core: LiveSyncCore); + saveSnapshot(snapshot: (FileEventItem | FileEventItemSentinel)[]): Promise; + loadSnapshot(): Promise<(FileEventItem | FileEventItemSentinel)[] | null>; +} +/** + * Obsidian-specific status adapter + */ +declare class ObsidianStatusAdapter implements IStorageEventStatusAdapter { + private fileProcessing; + constructor(fileProcessing: FileProcessingService); + updateStatus(status: { + batched: number; + processing: number; + totalQueued: number; + }): void; +} +/** + * Obsidian-specific converter adapter + */ +declare class ObsidianConverterAdapter implements IStorageEventConverterAdapter { + toFileInfo(file: TFile, deleted?: boolean): UXFileInfoStub; + toInternalFileInfo(path: FilePath): UXInternalFileInfoStub; +} +/** + * Obsidian-specific watch adapter + */ +declare class ObsidianWatchAdapter implements IStorageEventWatchAdapter { + private plugin; + constructor(plugin: ObsidianLiveSyncPlugin); + beginWatch(handlers: IStorageEventWatchHandlers): Promise; +} +/** + * Composite adapter for Obsidian StorageEventManager + */ +export declare class ObsidianStorageEventManagerAdapter implements IStorageEventManagerAdapter { + readonly typeGuard: ObsidianTypeGuardAdapter; + readonly persistence: ObsidianPersistenceAdapter; + readonly watch: ObsidianWatchAdapter; + readonly status: ObsidianStatusAdapter; + readonly converter: ObsidianConverterAdapter; + constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore, fileProcessing: FileProcessingService); +} +export {}; diff --git a/_types/managers/StorageEventManagerObsidian.d.ts b/_types/managers/StorageEventManagerObsidian.d.ts new file mode 100644 index 0000000..b61438d --- /dev/null +++ b/_types/managers/StorageEventManagerObsidian.d.ts @@ -0,0 +1,13 @@ +import type { FilePath } from "@lib/common/models/db.type"; +import type ObsidianLiveSyncPlugin from "@/main"; +import type { LiveSyncCore } from "@/main"; +import { StorageEventManagerBase, type StorageEventManagerBaseDependencies } from "@lib/managers/StorageEventManager"; +import { ObsidianStorageEventManagerAdapter } from "./ObsidianStorageEventManagerAdapter"; +export declare class StorageEventManagerObsidian extends StorageEventManagerBase { + core: LiveSyncCore; + constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore, dependencies: StorageEventManagerBaseDependencies); + /** + * Override _watchVaultRawEvents to add Obsidian-specific logic + */ + protected _watchVaultRawEvents(path: FilePath): Promise; +} diff --git a/_types/modules/AbstractModule.d.ts b/_types/modules/AbstractModule.d.ts new file mode 100644 index 0000000..03a2c3e --- /dev/null +++ b/_types/modules/AbstractModule.d.ts @@ -0,0 +1,27 @@ +import type { AnyEntry, FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { IMinimumLiveSyncCommands, LiveSyncBaseCore } from "@/LiveSyncBaseCore"; +import type { ServiceContext } from "@lib/services/base/ServiceBase"; +export declare abstract class AbstractModule = LiveSyncBaseCore> { + core: T; + _log: (msg: unknown, level?: import("octagonal-wheels/common/logger").LOG_LEVEL, key?: string) => void; + get services(): import("../lib/src/services/InjectableServices").InjectableServiceHub; + addCommand: (command: TCommand) => TCommand; + registerView: (type: string, factory: (leaf: any) => any) => void; + addRibbonIcon: (icon: string, title: string, callback: (evt: MouseEvent) => any) => HTMLElement; + registerObsidianProtocolHandler: (action: string, handler: (params: Record) => any) => void; + get localDatabase(): import("../lib/src/pouchdb/LiveSyncLocalDB").LiveSyncLocalDB; + get settings(): import("../lib/src/common/types").ObsidianLiveSyncSettings; + set settings(value: import("../lib/src/common/types").ObsidianLiveSyncSettings); + getPath(entry: AnyEntry): FilePathWithPrefix; + getPathWithoutPrefix(entry: AnyEntry): FilePathWithPrefix; + onBindFunction(core: T, services: typeof core.services): void; + constructor(core: T); + saveSettings: () => Promise; + addTestResult(key: string, value: boolean, summary?: string, message?: string): void; + testDone(result?: boolean): Promise; + testFail(message: string): Promise; + _test(key: string, process: () => Promise): Promise; + isMainReady(): boolean; + isMainSuspended(): boolean; + isDatabaseReady(): boolean; +} diff --git a/_types/modules/AbstractObsidianModule.d.ts b/_types/modules/AbstractObsidianModule.d.ts new file mode 100644 index 0000000..d7bf3f1 --- /dev/null +++ b/_types/modules/AbstractObsidianModule.d.ts @@ -0,0 +1,15 @@ +import type { Prettify } from "@lib/common/models/shared.type.util"; +import type { LiveSyncCore } from "@/main"; +import type ObsidianLiveSyncPlugin from "@/main"; +import { AbstractModule } from "./AbstractModule.ts"; +import type { ChainableExecuteFunction, OverridableFunctionsKeys } from "./ModuleTypes"; +export type IObsidianModuleBase = OverridableFunctionsKeys; +export type IObsidianModule = Prettify>; +export type ModuleKeys = keyof IObsidianModule; +export type ChainableModuleProps = ChainableExecuteFunction; +export declare abstract class AbstractObsidianModule extends AbstractModule { + plugin: ObsidianLiveSyncPlugin; + get app(): import("obsidian").App; + constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore); + isThisModuleEnabled(): boolean; +} diff --git a/_types/modules/ModuleTypes.d.ts b/_types/modules/ModuleTypes.d.ts new file mode 100644 index 0000000..4f16c1a --- /dev/null +++ b/_types/modules/ModuleTypes.d.ts @@ -0,0 +1,30 @@ +import type { Prettify } from "@lib/common/models/shared.type.util"; +import type { LiveSyncCore } from "@/main"; +export type OverridableFunctionsKeys = { + [K in keyof T as K extends `$${string}` ? K : never]: T[K]; +}; +export type ChainableExecuteFunction = { + [K in keyof T as K extends `$${string}` ? T[K] extends (...args: any) => ChainableFunctionResult ? K : never : never]: T[K]; +}; +export type ICoreModuleBase = OverridableFunctionsKeys; +export type ICoreModule = Prettify>; +export type CoreModuleKeys = keyof ICoreModule; +export type ChainableFunctionResult = Promise | Promise | Promise | Promise; +export type ChainableFunctionResultOrAll = Promise; +type AllExecuteFunction = { + [K in keyof T as K extends `$all${string}` ? T[K] extends (...args: any[]) => ChainableFunctionResultOrAll ? K : never : never]: T[K]; +}; +type EveryExecuteFunction = { + [K in keyof T as K extends `$every${string}` ? T[K] extends (...args: any[]) => ChainableFunctionResult ? K : never : never]: T[K]; +}; +type AnyExecuteFunction = { + [K in keyof T as K extends `$any${string}` ? T[K] extends (...args: any[]) => ChainableFunctionResult ? K : never : never]: T[K]; +}; +type InjectableFunction = { + [K in keyof T as K extends `$$${string}` ? (T[K] extends (...args: any[]) => any ? K : never) : never]: T[K]; +}; +export type AllExecuteProps = AllExecuteFunction; +export type EveryExecuteProps = EveryExecuteFunction; +export type AnyExecuteProps = AnyExecuteFunction; +export type AllInjectableProps = InjectableFunction; +export {}; diff --git a/_types/modules/core/ModulePeriodicProcess.d.ts b/_types/modules/core/ModulePeriodicProcess.d.ts new file mode 100644 index 0000000..303d97f --- /dev/null +++ b/_types/modules/core/ModulePeriodicProcess.d.ts @@ -0,0 +1,14 @@ +import { PeriodicProcessor } from "@/common/PeriodicProcessor"; +import type { LiveSyncCore } from "@/main"; +import { AbstractModule } from "@/modules/AbstractModule"; +export declare class ModulePeriodicProcess extends AbstractModule { + periodicSyncProcessor: PeriodicProcessor; + disablePeriodic(): Promise; + resumePeriodic(): Promise; + private _allOnUnload; + private _everyBeforeRealizeSetting; + private _everyBeforeSuspendProcess; + private _everyAfterResumeProcess; + private _everyAfterRealizeSetting; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/core/ModuleReplicator.d.ts b/_types/modules/core/ModuleReplicator.d.ts new file mode 100644 index 0000000..5f870cb --- /dev/null +++ b/_types/modules/core/ModuleReplicator.d.ts @@ -0,0 +1,24 @@ +import { AbstractModule } from "@/modules/AbstractModule"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { RemoteType } from "@lib/common/models/setting.type"; +import type { LiveSyncCore } from "@/main"; +import { ReplicateResultProcessor } from "./ReplicateResultProcessor"; +export declare class ModuleReplicator extends AbstractModule { + _replicatorType?: RemoteType; + processor: ReplicateResultProcessor; + private _unresolvedErrorManager; + clearErrors(): void; + private _everyOnloadAfterLoadSettings; + _onReplicatorInitialised(): Promise; + _everyOnDatabaseInitialized(showNotice: boolean): Promise; + _everyBeforeReplicate(showMessage: boolean): Promise; + /** + * obsolete method. No longer maintained and will be removed in the future. + * @deprecated v0.24.17 + * @param showMessage If true, show message to the user. + */ + cleaned(showMessage: boolean): Promise; + private onReplicationFailed; + _parseReplicationResult(docs: Array>): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/core/ModuleReplicatorCouchDB.d.ts b/_types/modules/core/ModuleReplicatorCouchDB.d.ts new file mode 100644 index 0000000..3e7bdfc --- /dev/null +++ b/_types/modules/core/ModuleReplicatorCouchDB.d.ts @@ -0,0 +1,9 @@ +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator"; +import { AbstractModule } from "@/modules/AbstractModule"; +import type { LiveSyncCore } from "@/main"; +export declare class ModuleReplicatorCouchDB extends AbstractModule { + _anyNewReplicator(settingOverride?: Partial): Promise; + _everyAfterResumeProcess(): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/core/ModuleReplicatorMinIO.d.ts b/_types/modules/core/ModuleReplicatorMinIO.d.ts new file mode 100644 index 0000000..0378fe9 --- /dev/null +++ b/_types/modules/core/ModuleReplicatorMinIO.d.ts @@ -0,0 +1,8 @@ +import type { RemoteDBSettings } from "@lib/common/models/setting.type"; +import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator"; +import type { LiveSyncCore } from "@/main"; +import { AbstractModule } from "@/modules/AbstractModule"; +export declare class ModuleReplicatorMinIO extends AbstractModule { + _anyNewReplicator(settingOverride?: Partial): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/core/ReplicateResultProcessor.d.ts b/_types/modules/core/ReplicateResultProcessor.d.ts new file mode 100644 index 0000000..a18bc72 --- /dev/null +++ b/_types/modules/core/ReplicateResultProcessor.d.ts @@ -0,0 +1,115 @@ +import type { AnyEntry, LoadedEntry, MetaEntry } from "@lib/common/models/db.type"; +import type { EntryDoc } from "@lib/common/models/db.definition"; +import type { ModuleReplicator } from "./ModuleReplicator"; +import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2"; +import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; +export declare class ReplicateResultProcessor { + private log; + private logError; + private replicator; + constructor(replicator: ModuleReplicator); + get localDatabase(): import("../../lib/src/pouchdb/LiveSyncLocalDB").LiveSyncLocalDB; + get services(): import("../../lib/src/services/InjectableServices").InjectableServiceHub; + get core(): LiveSyncBaseCore; + getPath(entry: AnyEntry): string; + suspend(): void; + resume(): void; + private _suspended; + get isSuspended(): boolean; + /** + * Take a snapshot of the current processing state. + * This snapshot is stored in the KV database for recovery on restart. + */ + protected _takeSnapshot(): Promise; + /** + * Trigger taking a snapshot. + */ + protected _triggerTakeSnapshot(): void; + /** + * Throttled version of triggerTakeSnapshot. + */ + protected triggerTakeSnapshot: import("octagonal-wheels/function").ThrottledFunction<() => void>; + /** + * Restore from snapshot. + */ + restoreFromSnapshot(): Promise; + private _restoreFromSnapshot; + /** + * Restore from snapshot only once. + * @returns Promise that resolves when restoration is complete. + */ + restoreFromSnapshotOnce(): Promise; + /** + * Perform the given procedure while counting the concurrency. + * @param proc async procedure to perform + * @param countValue reactive source to count concurrency + * @returns result of the procedure + */ + withCounting(proc: () => Promise, countValue: ReactiveSource): Promise; + /** + * Report the current status. + */ + protected reportStatus(): void; + /** + * Enqueue all the given changes for processing. + * @param changes Changes to enqueue + */ + enqueueAll(changes: PouchDB.Core.ExistingDocument[]): void; + /** + * Process the change if it is not a document change. + * @param change Change to process + * @returns True if the change was processed; false otherwise + */ + protected processIfNonDocumentChange(change: PouchDB.Core.ExistingDocument): boolean; + /** + * Queue of changes to be processed. + */ + private _queuedChanges; + /** + * List of changes being processed. + */ + private _processingChanges; + /** + * Enqueue the given document change for processing. + * @param doc Document change to enqueue + * @returns + */ + protected enqueueChange(doc: PouchDB.Core.ExistingDocument): void; + /** + * Trigger processing of the queued changes. + */ + protected triggerProcessQueue(): void; + /** + * Semaphore to limit concurrent processing. + * This is the per-id semaphore + concurrency-control (max 10 concurrent = 10 documents being processed at the same time). + */ + private _semaphore; + /** + * Flag indicating whether the process queue is currently running. + */ + private _isRunningProcessQueue; + /** + * Process the queued changes. + */ + private runProcessQueue; + /** + * Parse the given document change. + * @param change + * @returns + */ + parseDocumentChange(change: PouchDB.Core.ExistingDocument): Promise; + protected applyToDatabase(doc: PouchDB.Core.ExistingDocument): Promise; + private _applyToDatabase; + /** + * Phase 3: Apply the given entry to storage. + * @param entry + * @returns + */ + protected applyToStorage(entry: MetaEntry): Promise; + /** + * Check whether processing is required for the given document. + * @param dbDoc Document to check + * @returns True if processing is required; false otherwise + */ + protected checkIsChangeRequiredForDatabaseProcessing(dbDoc: LoadedEntry): Promise; +} diff --git a/_types/modules/coreFeatures/ModuleConflictChecker.d.ts b/_types/modules/coreFeatures/ModuleConflictChecker.d.ts new file mode 100644 index 0000000..cd7c1fd --- /dev/null +++ b/_types/modules/coreFeatures/ModuleConflictChecker.d.ts @@ -0,0 +1,13 @@ +import { AbstractModule } from "@/modules/AbstractModule.ts"; +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import { QueueProcessor } from "octagonal-wheels/concurrency/processor"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleConflictChecker extends AbstractModule { + _queueConflictCheckIfOpen(file: FilePathWithPrefix): Promise; + _queueConflictCheck(file: FilePathWithPrefix): Promise; + _waitForAllConflictProcessed(): Promise; + conflictResolveQueue: QueueProcessor; + conflictCheckQueue: QueueProcessor; + onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void; +} diff --git a/_types/modules/coreFeatures/ModuleConflictResolver.d.ts b/_types/modules/coreFeatures/ModuleConflictResolver.d.ts new file mode 100644 index 0000000..83b2b02 --- /dev/null +++ b/_types/modules/coreFeatures/ModuleConflictResolver.d.ts @@ -0,0 +1,18 @@ +import { AbstractModule } from "@/modules/AbstractModule.ts"; +import type { diff_check_result } from "@lib/common/models/diff.definition"; +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts"; +import type { LiveSyncCore } from "@/main.ts"; +declare global { + interface LSEvents { + "conflict-cancelled": FilePathWithPrefix; + } +} +export declare class ModuleConflictResolver extends AbstractModule { + private _resolveConflictByDeletingRev; + checkConflictAndPerformAutoMerge(path: FilePathWithPrefix): Promise; + private _resolveConflict; + private _anyResolveConflictByNewest; + private _resolveAllConflictedFilesByNewerOnes; + onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void; +} diff --git a/_types/modules/coreFeatures/ModuleResolveMismatchedTweaks.d.ts b/_types/modules/coreFeatures/ModuleResolveMismatchedTweaks.d.ts new file mode 100644 index 0000000..8bb035b --- /dev/null +++ b/_types/modules/coreFeatures/ModuleResolveMismatchedTweaks.d.ts @@ -0,0 +1,35 @@ +import type { TweakValues } from "@lib/common/models/tweak.definition"; +import type { ObsidianLiveSyncSettings, RemoteDBSettings } from "@lib/common/models/setting.type"; +import { AbstractModule } from "@/modules/AbstractModule.ts"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleResolvingMismatchedTweaks extends AbstractModule { + private _hasNotifiedAutoAcceptCompatibleUndefined; + private _collectMismatchedTweakKeys; + private _selectNewerTweakSide; + private _shouldAutoAcceptCompatibleLossy; + /** + * Hook before saving settings, to check if there are changes in tweak values, and if so, + * update the tweakModified timestamp to current time. + * This allows other devices to know that the tweak values have been changed and decide whether to accept the new values based on the modification time. + * @param next + * @param previous + * @returns + */ + _onBeforeSaveSettingData(next: ObsidianLiveSyncSettings, previous: ObsidianLiveSyncSettings): Promise<{ + tweakModified: number; + } | undefined>; + _anyAfterConnectCheckFailed(): Promise; + _checkAndAskResolvingMismatchedTweaks(preferred: TweakValues): Promise<[TweakValues | boolean, boolean]>; + _askResolvingMismatchedTweaks(): Promise<"OK" | "CHECKAGAIN" | "IGNORE">; + _fetchRemotePreferredTweakValues(trialSetting: RemoteDBSettings): Promise; + _checkAndAskUseRemoteConfiguration(trialSetting: RemoteDBSettings): Promise<{ + result: false | TweakValues; + requireFetch: boolean; + }>; + _askUseRemoteConfiguration(trialSetting: RemoteDBSettings, preferred: TweakValues): Promise<{ + result: false | TweakValues; + requireFetch: boolean; + }>; + onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void; +} diff --git a/_types/modules/coreObsidian/UILib/dialogs.d.ts b/_types/modules/coreObsidian/UILib/dialogs.d.ts new file mode 100644 index 0000000..ce6a840 --- /dev/null +++ b/_types/modules/coreObsidian/UILib/dialogs.d.ts @@ -0,0 +1,53 @@ +import { ButtonComponent } from "@/deps.ts"; +import { App, FuzzySuggestModal, Modal, Plugin } from "@/deps.ts"; +import { type CompatIntervalHandle } from "@lib/common/coreEnvFunctions.ts"; +declare class AutoClosableModal extends Modal { + _closeByUnload(): void; + constructor(app: App); + onClose(): void; +} +export declare class InputStringDialog extends AutoClosableModal { + result: string | false; + onSubmit: (result: string | false) => void; + title: string; + key: string; + placeholder: string; + isManuallyClosed: boolean; + isPassword: boolean; + constructor(app: App, title: string, key: string, placeholder: string, isPassword: boolean, onSubmit: (result: string | false) => void); + onOpen(): void; + onClose(): void; +} +export declare class PopoverSelectString extends FuzzySuggestModal { + _app: App; + callback: ((e: string) => void) | undefined; + getItemsFun: () => string[]; + constructor(app: App, note: string, placeholder: string | undefined, getItemsFun: (() => string[]) | undefined, callback: (e: string) => void); + getItems(): string[]; + getItemText(item: string): string; + onChooseItem(item: string, evt: MouseEvent | KeyboardEvent): void; + onClose(): void; +} +export declare class MessageBox extends AutoClosableModal { + plugin: Plugin; + title: string; + contentMd: string; + buttons: T; + result: string | false; + isManuallyClosed: boolean; + defaultAction: string | undefined; + timeout: number | undefined; + timer: CompatIntervalHandle | undefined; + defaultButtonComponent: ButtonComponent | undefined; + wideButton: boolean; + onSubmit: (result: string | false) => void; + constructor(plugin: Plugin, title: string, contentMd: string, buttons: T, defaultAction: T[number], timeout: number | undefined, wideButton: boolean, onSubmit: (result: T[number] | false) => void); + onOpen(): void; + onClose(): void; +} +export declare function confirmWithMessage(plugin: Plugin, title: string, contentMd: string, buttons: T, defaultAction: T[number], timeout?: number): Promise; +export declare function confirmWithMessageWithWideButton(plugin: Plugin, title: string, contentMd: string, buttons: T, defaultAction: T[number], timeout?: number): Promise; +export declare const askYesNo: (app: App, message: string) => Promise<"yes" | "no">; +export declare const askSelectString: (app: App, message: string, items: string[]) => Promise; +export declare const askString: (app: App, title: string, key: string, placeholder: string, isPassword?: boolean) => Promise; +export {}; diff --git a/_types/modules/coreObsidian/storageLib/utilObsidian.d.ts b/_types/modules/coreObsidian/storageLib/utilObsidian.d.ts new file mode 100644 index 0000000..52f3840 --- /dev/null +++ b/_types/modules/coreObsidian/storageLib/utilObsidian.d.ts @@ -0,0 +1,10 @@ +import { TFile, type TAbstractFile, type TFolder } from "@/deps.ts"; +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { UXFileInfo, UXFileInfoStub, UXFolderInfo, UXInternalFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { LiveSyncCore } from "@/main.ts"; +import type { FileAccessObsidian } from "@/serviceModules/FileAccessObsidian.ts"; +export declare function TFileToUXFileInfo(core: LiveSyncCore, file: TFile, prefix?: string, deleted?: boolean): Promise; +export declare function InternalFileToUXFileInfo(fullPath: string, vaultAccess: FileAccessObsidian, prefix?: string): Promise; +export declare function TFileToUXFileInfoStub(file: TFile | TAbstractFile, deleted?: boolean): UXFileInfoStub; +export declare function InternalFileToUXFileInfoStub(filename: FilePathWithPrefix, deleted?: boolean): UXInternalFileInfoStub; +export declare function TFolderToUXFileInfoStub(file: TFolder): UXFolderInfo; diff --git a/_types/modules/essential/ModuleBasicMenu.d.ts b/_types/modules/essential/ModuleBasicMenu.d.ts new file mode 100644 index 0000000..02c80ad --- /dev/null +++ b/_types/modules/essential/ModuleBasicMenu.d.ts @@ -0,0 +1,6 @@ +import type { LiveSyncCore } from "@/main"; +import { AbstractModule } from "@/modules/AbstractModule"; +export declare class ModuleBasicMenu extends AbstractModule { + _everyOnloadStart(): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/essential/ModuleMigration.d.ts b/_types/modules/essential/ModuleMigration.d.ts new file mode 100644 index 0000000..bc750ad --- /dev/null +++ b/_types/modules/essential/ModuleMigration.d.ts @@ -0,0 +1,13 @@ +import { AbstractModule } from "@/modules/AbstractModule.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleMigration extends AbstractModule { + migrateUsingDoctor(skipRebuild?: boolean, activateReason?: string, forceRescan?: boolean): Promise; + migrateDisableBulkSend(): Promise; + initialMessage(): Promise; + askAgainForSetupURI(): Promise; + hasIncompleteDocs(force?: boolean): Promise; + hasCompromisedChunks(): Promise; + _everyOnFirstInitialize(): Promise; + _everyOnLayoutReady(): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/essentialObsidian/APILib/ObsHttpHandler.d.ts b/_types/modules/essentialObsidian/APILib/ObsHttpHandler.d.ts new file mode 100644 index 0000000..0a62bae --- /dev/null +++ b/_types/modules/essentialObsidian/APILib/ObsHttpHandler.d.ts @@ -0,0 +1,16 @@ +import { FetchHttpHandler, type FetchHttpHandlerOptions } from "@smithy/fetch-http-handler"; +import { HttpRequest, HttpResponse, type HttpHandlerOptions } from "@smithy/protocol-http"; +/** + * This is close to origin implementation of FetchHttpHandler + * https://github.com/aws/aws-sdk-js-v3/blob/main/packages/fetch-http-handler/src/fetch-http-handler.ts + * that is released under Apache 2 License. + * But this uses Obsidian requestUrl instead. + */ +export declare class ObsHttpHandler extends FetchHttpHandler { + requestTimeoutInMs: number | undefined; + reverseProxyNoSignUrl: string | undefined; + constructor(options?: FetchHttpHandlerOptions, reverseProxyNoSignUrl?: string); + handle(request: HttpRequest, { abortSignal }?: HttpHandlerOptions): Promise<{ + response: HttpResponse; + }>; +} diff --git a/_types/modules/essentialObsidian/ModuleObsidianEvents.d.ts b/_types/modules/essentialObsidian/ModuleObsidianEvents.d.ts new file mode 100644 index 0000000..50818a6 --- /dev/null +++ b/_types/modules/essentialObsidian/ModuleObsidianEvents.d.ts @@ -0,0 +1,26 @@ +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +import { type TFile } from "@/deps.ts"; +import { type ReactiveSource } from "octagonal-wheels/dataobject/reactive"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleObsidianEvents extends AbstractObsidianModule { + _everyOnloadStart(): Promise; + __performAppReload(): void; + initialCallback: (() => unknown) | undefined; + swapSaveCommand(): void; + registerWatchEvents(): void; + hasFocus: boolean; + isLastHidden: boolean; + setHasFocus(hasFocus: boolean): void; + watchWindowVisibility(): void; + watchOnline(): void; + watchOnlineAsync(): Promise; + watchWindowVisibilityAsync(): Promise; + watchWorkspaceOpen(file: TFile | null): void; + watchWorkspaceOpenAsync(file: TFile): Promise; + _everyOnLayoutReady(): Promise; + private _askReload; + _totalProcessingCount?: ReactiveSource; + private _scheduleAppReload; + _isReloadingScheduled(): boolean; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/essentialObsidian/ModuleObsidianMenu.d.ts b/_types/modules/essentialObsidian/ModuleObsidianMenu.d.ts new file mode 100644 index 0000000..3f80f06 --- /dev/null +++ b/_types/modules/essentialObsidian/ModuleObsidianMenu.d.ts @@ -0,0 +1,6 @@ +import type { LiveSyncCore } from "@/main.ts"; +import { AbstractModule } from "@/modules/AbstractModule.ts"; +export declare class ModuleObsidianMenu extends AbstractModule { + _everyOnloadStart(): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/extras/ModuleDev.d.ts b/_types/modules/extras/ModuleDev.d.ts new file mode 100644 index 0000000..4d23da9 --- /dev/null +++ b/_types/modules/extras/ModuleDev.d.ts @@ -0,0 +1,12 @@ +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleDev extends AbstractObsidianModule { + _everyOnloadStart(): Promise; + onMissingTranslation(key: string): Promise; + private _everyOnloadAfterLoadSettings; + _everyOnLayoutReady(): Promise; + testResults: import("svelte/store").Writable<[boolean, string, string][]>; + private _addTestResult; + private _everyModuleTest; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/extras/devUtil/TestPaneView.d.ts b/_types/modules/extras/devUtil/TestPaneView.d.ts new file mode 100644 index 0000000..045cbc2 --- /dev/null +++ b/_types/modules/extras/devUtil/TestPaneView.d.ts @@ -0,0 +1,24 @@ +import { ItemView, WorkspaceLeaf } from "@/deps.ts"; +import TestPaneComponent from "./TestPane.svelte"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import type { ModuleDev } from "@/modules/extras/ModuleDev.ts"; +export declare const VIEW_TYPE_TEST = "ols-pane-test"; +declare global { + interface LSEvents { + "debug-sync-status": string[]; + } +} +export declare class TestPaneView extends ItemView { + component?: TestPaneComponent; + plugin: ObsidianLiveSyncPlugin; + moduleDev: ModuleDev; + icon: string; + title: string; + navigation: boolean; + getIcon(): string; + constructor(leaf: WorkspaceLeaf, plugin: ObsidianLiveSyncPlugin, moduleDev: ModuleDev); + getViewType(): string; + getDisplayText(): string; + onOpen(): Promise; + onClose(): Promise; +} diff --git a/_types/modules/extras/devUtil/testUtils.d.ts b/_types/modules/extras/devUtil/testUtils.d.ts new file mode 100644 index 0000000..ae5130e --- /dev/null +++ b/_types/modules/extras/devUtil/testUtils.d.ts @@ -0,0 +1,3 @@ +import type ObsidianLiveSyncPlugin from "@/main.ts"; +export declare function enableTestFunction(plugin_: ObsidianLiveSyncPlugin): void; +export declare function addDebugFileLog(message: unknown, stackLog?: boolean): void; diff --git a/_types/modules/features/DocumentHistory/DocumentHistoryModal.d.ts b/_types/modules/features/DocumentHistory/DocumentHistoryModal.d.ts new file mode 100644 index 0000000..b101fe9 --- /dev/null +++ b/_types/modules/features/DocumentHistory/DocumentHistoryModal.d.ts @@ -0,0 +1,69 @@ +import { TFile, Modal, App } from "@/deps.ts"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import type { DocumentID, FilePathWithPrefix, LoadedEntry } from "@lib/common/models/db.type"; +import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts"; +export declare class DocumentHistoryModal extends Modal { + plugin: ObsidianLiveSyncPlugin; + core: LiveSyncBaseCore; + get services(): import("../../../lib/src/services/InjectableServices").InjectableServiceHub; + range: HTMLInputElement; + contentView: HTMLDivElement; + info: HTMLDivElement; + fileInfo: HTMLDivElement; + showDiff: boolean; + diffOnly: boolean; + id?: DocumentID; + file: FilePathWithPrefix; + revs_info: PouchDB.Core.RevisionInfo[]; + currentDoc?: LoadedEntry; + currentText: string; + currentDeleted: boolean; + initialRev?: string; + currentDiffIndex: number; + diffNavContainer: HTMLDivElement; + diffNavIndicator: HTMLSpanElement; + diffOnlyLabel: HTMLLabelElement; + searchKeyword: string; + searchResults: { + rev: string; + index: number; + matchType: "Content" | "Diff"; + }[]; + currentSearchIndex: number; + searchResultIndicator: HTMLSpanElement; + searchProgressIndicator: HTMLSpanElement; + searchTimeout: number | null; + constructor(app: App, core: LiveSyncBaseCore, plugin: ObsidianLiveSyncPlugin, file: TFile | FilePathWithPrefix, id?: DocumentID, revision?: string); + loadFile(initialRev?: string): Promise; + loadRevs(initialRev?: string): Promise; + BlobURLs: Map; + revokeURL(key: string): void; + generateBlobURL(key: string, data: Uint8Array): string; + prepareContentView(usePreformatted?: boolean): void; + appendTextDiff(diff: [number, string][]): void; + appendSearchHighlightedText(container: HTMLElement, text: string): void; + appendImageDiff(baseSrc: string, overlaySrc?: string): void; + appendDeletedNotice(usePreformatted?: boolean): void; + showExactRev(rev: string): Promise; + /** + * Navigate to the previous or next diff block in the content view. + * Only effective when diff highlighting is enabled. + */ + navigateDiff(direction: "prev" | "next"): void; + /** + * Reset the diff navigation index and update the indicator. + */ + resetDiffNavigation(): void; + /** + * Show or hide the diff navigation buttons based on the showDiff state. + */ + updateDiffNavVisibility(): void; + /** + * Search through the last 100 revisions for the given keyword. + */ + performSearch(keyword: string): Promise; + updateSearchUI(): void; + navigateSearch(direction: "prev" | "next"): void; + onOpen(): void; + onClose(): void; +} diff --git a/_types/modules/features/GlobalHistory/GlobalHistoryView.d.ts b/_types/modules/features/GlobalHistory/GlobalHistoryView.d.ts new file mode 100644 index 0000000..8c34e5f --- /dev/null +++ b/_types/modules/features/GlobalHistory/GlobalHistoryView.d.ts @@ -0,0 +1,18 @@ +import { WorkspaceLeaf } from "@/deps.ts"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import { SvelteItemView } from "@/common/SvelteItemView.ts"; +export declare const VIEW_TYPE_GLOBAL_HISTORY = "global-history"; +export declare class GlobalHistoryView extends SvelteItemView { + instantiateComponent(target: HTMLElement): { + $on?(type: string, callback: (e: any) => void): () => void; + $set?(props: Partial>): void; + } & Record; + plugin: ObsidianLiveSyncPlugin; + icon: string; + title: string; + navigation: boolean; + getIcon(): string; + constructor(leaf: WorkspaceLeaf, plugin: ObsidianLiveSyncPlugin); + getViewType(): string; + getDisplayText(): string; +} diff --git a/_types/modules/features/InteractiveConflictResolving/ConflictResolveModal.d.ts b/_types/modules/features/InteractiveConflictResolving/ConflictResolveModal.d.ts new file mode 100644 index 0000000..f1edca1 --- /dev/null +++ b/_types/modules/features/InteractiveConflictResolving/ConflictResolveModal.d.ts @@ -0,0 +1,34 @@ +import { App, Modal } from "@/deps.ts"; +import { CANCELLED, LEAVE_TO_SUBSEQUENT } from "@lib/common/models/shared.const.symbols"; +import type { diff_result } from "@lib/common/models/diff.definition"; +import { eventHub } from "@/common/events.ts"; +export type MergeDialogResult = typeof CANCELLED | typeof LEAVE_TO_SUBSEQUENT | string; +declare global { + interface Slips extends LSSlips { + "conflict-resolved": typeof CANCELLED | MergeDialogResult; + } +} +export declare class ConflictResolveModal extends Modal { + result: diff_result; + filename: string; + response: MergeDialogResult; + isClosed: boolean; + consumed: boolean; + title: string; + pluginPickMode: boolean; + localName: string; + remoteName: string; + offEvent?: ReturnType; + currentDiffIndex: number; + diffView: HTMLDivElement; + diffNavIndicator: HTMLSpanElement; + constructor(app: App, filename: string, diff: diff_result, pluginPickMode?: boolean, remoteName?: string); + appendDiffFragment(container: HTMLDivElement, text: string, cls: string): void; + appendVersionInfo(container: HTMLDivElement, cls: string, name: string, date: string): void; + navigateDiff(direction: "prev" | "next"): void; + resetDiffNavigation(): void; + onOpen(): void; + sendResponse(result: MergeDialogResult): void; + onClose(): void; + waitForResult(): Promise; +} diff --git a/_types/modules/features/Log/LogPaneView.d.ts b/_types/modules/features/Log/LogPaneView.d.ts new file mode 100644 index 0000000..cd39422 --- /dev/null +++ b/_types/modules/features/Log/LogPaneView.d.ts @@ -0,0 +1,18 @@ +import { WorkspaceLeaf } from "@/deps.ts"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import { SvelteItemView } from "@/common/SvelteItemView.ts"; +export declare const VIEW_TYPE_LOG = "log-log"; +export declare class LogPaneView extends SvelteItemView { + instantiateComponent(target: HTMLElement): { + $on?(type: string, callback: (e: any) => void): () => void; + $set?(props: Partial>): void; + } & Record; + plugin: ObsidianLiveSyncPlugin; + icon: string; + title: string; + navigation: boolean; + getIcon(): string; + constructor(leaf: WorkspaceLeaf, plugin: ObsidianLiveSyncPlugin); + getViewType(): string; + getDisplayText(): import("octagonal-wheels/common/types").TaggedType; +} diff --git a/_types/modules/features/ModuleGlobalHistory.d.ts b/_types/modules/features/ModuleGlobalHistory.d.ts new file mode 100644 index 0000000..04a9f15 --- /dev/null +++ b/_types/modules/features/ModuleGlobalHistory.d.ts @@ -0,0 +1,6 @@ +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +export declare class ModuleObsidianGlobalHistory extends AbstractObsidianModule { + _everyOnloadStart(): Promise; + showGlobalHistory(): void; + onBindFunction(core: typeof this.core, services: typeof core.services): void; +} diff --git a/_types/modules/features/ModuleInteractiveConflictResolver.d.ts b/_types/modules/features/ModuleInteractiveConflictResolver.d.ts new file mode 100644 index 0000000..32b4728 --- /dev/null +++ b/_types/modules/features/ModuleInteractiveConflictResolver.d.ts @@ -0,0 +1,12 @@ +import type { FilePathWithPrefix } from "@lib/common/models/db.type"; +import type { diff_result } from "@lib/common/models/diff.definition"; +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleInteractiveConflictResolver extends AbstractObsidianModule { + _everyOnloadStart(): Promise; + _anyResolveConflictByUI(filename: FilePathWithPrefix, conflictCheckResult: diff_result): Promise; + allConflictCheck(): Promise; + pickFileForResolve(): Promise; + _allScanStat(): Promise; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/features/ModuleLog.d.ts b/_types/modules/features/ModuleLog.d.ts new file mode 100644 index 0000000..de43f80 --- /dev/null +++ b/_types/modules/features/ModuleLog.d.ts @@ -0,0 +1,47 @@ +import { type ReactiveValue } from "octagonal-wheels/dataobject/reactive"; +import type { LOG_LEVEL } from "@lib/common/logger"; +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +import { Notice } from "@/deps.ts"; +import { P2PLogCollector } from "@lib/replication/trystero/P2PLogCollector.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare const MARK_DONE = "\u2009\u2009"; +export declare class ModuleLog extends AbstractObsidianModule { + statusBar?: HTMLElement; + statusDiv?: HTMLElement; + statusLine?: HTMLDivElement; + logMessage?: HTMLDivElement; + logHistory?: HTMLDivElement; + messageArea?: HTMLDivElement; + statusBarLabels: ReactiveValue<{ + message: string; + status: string; + }>; + statusLog: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + activeFileStatus: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; + notifies: { + [key: string]: { + notice: Notice; + count: number; + }; + }; + p2pLogCollector: P2PLogCollector; + observeForLogs(): void; + private _everyOnload; + adjustStatusDivPosition(): void; + getActiveFileStatus(): Promise; + setFileStatus(): Promise; + updateMessageArea(): Promise; + onActiveLeafChange(): void; + nextFrameQueue: ReturnType | undefined; + logLines: { + ttl: number; + message: string; + }[]; + applyStatusBarText(): void; + private _allStartOnUnload; + _everyOnloadStart(): Promise; + private _everyOnloadAfterLoadSettings; + writeLogToTheFile(now: Date, vaultName: string, newMessage: string): void; + __addLog(message: unknown, level?: LOG_LEVEL, key?: string): void; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/features/ModuleObsidianDocumentHistory.d.ts b/_types/modules/features/ModuleObsidianDocumentHistory.d.ts new file mode 100644 index 0000000..849086f --- /dev/null +++ b/_types/modules/features/ModuleObsidianDocumentHistory.d.ts @@ -0,0 +1,9 @@ +import { type TFile } from "@/deps.ts"; +import type { FilePathWithPrefix, DocumentID } from "@lib/common/models/db.type"; +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +export declare class ModuleObsidianDocumentHistory extends AbstractObsidianModule { + _everyOnloadStart(): Promise; + showHistory(file: TFile | FilePathWithPrefix, id?: DocumentID): void; + fileHistory(): Promise; + onBindFunction(core: typeof this.core, services: typeof core.services): void; +} diff --git a/_types/modules/features/ModuleObsidianSettingAsMarkdown.d.ts b/_types/modules/features/ModuleObsidianSettingAsMarkdown.d.ts new file mode 100644 index 0000000..1959796 --- /dev/null +++ b/_types/modules/features/ModuleObsidianSettingAsMarkdown.d.ts @@ -0,0 +1,22 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import { AbstractModule } from "@/modules/AbstractModule.ts"; +import type { ServiceContext } from "@lib/services/base/ServiceBase.ts"; +import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleObsidianSettingsAsMarkdown extends AbstractModule { + _everyOnloadStart(): Promise; + extractSettingFromWholeText(data: string): { + preamble: string; + body: string; + postscript: string; + }; + parseSettingFromMarkdown(filename: string, data?: string): Promise<{ + preamble: string; + body: string; + postscript: string; + }>; + checkAndApplySettingFromMarkdown(filename: string, automated?: boolean): Promise; + generateSettingForMarkdown(settings?: ObsidianLiveSyncSettings, keepCredential?: boolean): Partial; + saveSettingToMarkdown(filename: string): Promise; + onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void; +} diff --git a/_types/modules/features/ModuleObsidianSettingTab.d.ts b/_types/modules/features/ModuleObsidianSettingTab.d.ts new file mode 100644 index 0000000..1e84dc0 --- /dev/null +++ b/_types/modules/features/ModuleObsidianSettingTab.d.ts @@ -0,0 +1,10 @@ +import { ObsidianLiveSyncSettingTab } from "./SettingDialogue/ObsidianLiveSyncSettingTab.ts"; +import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleObsidianSettingDialogue extends AbstractObsidianModule { + settingTab: ObsidianLiveSyncSettingTab; + _everyOnloadStart(): Promise; + openSetting(): void; + get appId(): string; + onBindFunction(core: LiveSyncCore, services: typeof core.services): void; +} diff --git a/_types/modules/features/SettingDialogue/LiveSyncSetting.d.ts b/_types/modules/features/SettingDialogue/LiveSyncSetting.d.ts new file mode 100644 index 0000000..8f03b36 --- /dev/null +++ b/_types/modules/features/SettingDialogue/LiveSyncSetting.d.ts @@ -0,0 +1,53 @@ +import { Setting, TextComponent, type ToggleComponent, type DropdownComponent, ButtonComponent, type TextAreaComponent, type ValueComponent } from "@/deps.ts"; +import type { ConfigurationItem } from "@lib/common/models/shared.definition.configNames"; +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import { type AllSettingItemKey, type AllSettings, type AllStringItemKey, type AllNumericItemKey, type AllBooleanItemKey } from "./settingConstants.ts"; +import { type AutoWireOption, type OnUpdateResult } from "./SettingPane.ts"; +export declare class LiveSyncSetting extends Setting { + autoWiredComponent?: TextComponent | ToggleComponent | DropdownComponent | ButtonComponent | TextAreaComponent; + applyButtonComponent?: ButtonComponent; + selfKey?: AllSettingItemKey; + watchDirtyKeys: AllSettingItemKey[]; + holdValue: boolean; + static env: ObsidianLiveSyncSettingTab; + descBuf: string | DocumentFragment; + nameBuf: string | DocumentFragment; + placeHolderBuf: string; + hasPassword: boolean; + invalidateValue?: () => void; + setValue?: (value: unknown) => void; + constructor(containerEl: HTMLElement); + setDesc(desc: string | DocumentFragment): this; + setName(name: string | DocumentFragment): this; + setAuto(key: AllSettingItemKey, opt?: AutoWireOption): this; + autoWireSetting(key: AllSettingItemKey, opt?: AutoWireOption): { + name: string; + desc?: string; + placeHolder?: string; + status?: "BETA" | "ALPHA" | "EXPERIMENTAL"; + obsolete?: boolean; + level?: import("@lib/common/models/shared.definition.configNames").ConfigLevel; + isHidden?: boolean; + isAdvanced?: boolean; + } | undefined; + autoWireComponent(component: ValueComponent, conf?: ConfigurationItem, opt?: AutoWireOption): void; + commitValue(value: AllSettings[T]): Promise; + autoWireText(key: AllStringItemKey, opt?: AutoWireOption): this; + autoWireTextArea(key: AllStringItemKey, opt?: AutoWireOption): this; + autoWireNumeric(key: AllNumericItemKey, opt: AutoWireOption & { + clampMin?: number; + clampMax?: number; + acceptZero?: boolean; + }): this; + autoWireToggle(key: AllBooleanItemKey, opt?: AutoWireOption): this; + autoWireDropDown(key: AllStringItemKey, opt: AutoWireOption & { + options: Record; + }): this; + addApplyButton(keys: AllSettingItemKey[], text?: string): this; + addOnUpdate(func: () => OnUpdateResult): this; + updateHandlers: Set<() => OnUpdateResult>; + prevStatus: OnUpdateResult; + _getComputedStatus(): OnUpdateResult; + _applyOnUpdateHandlers(): void; + _onUpdate(): void; +} diff --git a/_types/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.d.ts b/_types/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.d.ts new file mode 100644 index 0000000..eb0a2d8 --- /dev/null +++ b/_types/modules/features/SettingDialogue/ObsidianLiveSyncSettingTab.d.ts @@ -0,0 +1,100 @@ +import { App, PluginSettingTab } from "@/deps.ts"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import type ObsidianLiveSyncPlugin from "@/main.ts"; +import { type AllSettingItemKey, type AllStringItemKey, type AllNumericItemKey, type AllBooleanItemKey, type AllSettings, OnDialogSettingsDefault, type OnDialogSettings } from "./settingConstants.ts"; +import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts"; +import { JournalSyncMinio } from "@lib/replication/journal/objectstore/JournalSyncMinio.ts"; +import { type OnSavedHandler, type OnUpdateFunc, type OnUpdateResult, type UpdateFunction } from "./SettingPane.ts"; +export declare class ObsidianLiveSyncSettingTab extends PluginSettingTab { + plugin: ObsidianLiveSyncPlugin; + get core(): import("@/main.ts").LiveSyncCore; + get services(): import("../../../lib/src/services/InjectableServices.ts").InjectableServiceHub; + selectedScreen: string; + _editingSettings?: AllSettings; + get editingSettings(): AllSettings; + set editingSettings(v: AllSettings); + initialSettings?: typeof this.editingSettings; + /** + * Apply editing setting to the plug-in. + * @param keys setting keys for applying + */ + applySetting(keys: AllSettingItemKey[]): void; + applyAllSettings(): void; + saveLocalSetting(key: keyof typeof OnDialogSettingsDefault): Promise; + /** + * Apply and save setting to the plug-in. + * @param keys setting keys for applying + */ + saveSettings(keys: AllSettingItemKey[]): Promise; + /** + * Apply all editing setting to the plug-in. + * @param keys setting keys for applying + */ + saveAllDirtySettings(): Promise; + /** + * Invalidate buffered value and fetch the latest. + */ + requestUpdate(): void; + reloadAllLocalSettings(): { + configPassphrase: string; + preset: "" | "PERIODIC" | "LIVESYNC" | "DISABLE"; + syncMode: "ONEVENTS" | "PERIODIC" | "LIVESYNC"; + dummy: number; + deviceAndVaultName: string; + }; + computeAllLocalSettings(): Partial; + /** + * Reread all settings and request invalidate + */ + reloadAllSettings(skipUpdate?: boolean): void; + /** + * Reread each setting and request invalidate + */ + refreshSetting(key: AllSettingItemKey): void; + isDirty(key: AllSettingItemKey): boolean; + isSomeDirty(keys: AllSettingItemKey[]): boolean; + isConfiguredAs(key: AllStringItemKey, value: string): boolean; + isConfiguredAs(key: AllNumericItemKey, value: number): boolean; + isConfiguredAs(key: AllBooleanItemKey, value: boolean): boolean; + settingComponents: Setting[]; + controlledElementFunc: UpdateFunction[]; + onSavedHandlers: OnSavedHandler[]; + inWizard: boolean; + constructor(app: App, plugin: ObsidianLiveSyncPlugin); + testConnection(settingOverride?: Partial): Promise; + closeSetting(): void; + handleElement(element: HTMLElement, func: OnUpdateFunc): void; + createEl(el: HTMLElement, tag: T, o?: string | DomElementInfo, callback?: (el: HTMLElementTagNameMap[T]) => void, func?: OnUpdateFunc): HTMLElementTagNameMap[T]; + addEl(el: HTMLElement, tag: T, o?: string | DomElementInfo, callback?: (el: HTMLElementTagNameMap[T]) => void, func?: OnUpdateFunc): Promise>; + addOnSaved(key: T, func: (value: AllSettings[T]) => Promise | void): void; + resetEditingSettings(): void; + hide(): void; + isShown: boolean; + requestReload(): void; + manifestVersion: string; + lastVersion: number; + screenElements: { + [key: string]: HTMLElement[]; + }; + changeDisplay(screen: string): void; + enableMinimalSetup(): Promise; + menuEl?: HTMLElement; + addScreenElement(key: string, element: HTMLElement): void; + selectPane(event: Event): void; + isNeedRebuildLocal(): boolean; + isNeedRebuildRemote(): boolean; + isAnySyncEnabled(): boolean; + enableOnlySyncDisabled: OnUpdateFunc; + onlyOnP2POrCouchDB: () => OnUpdateResult; + onlyOnCouchDB: () => OnUpdateResult; + onlyOnMinIO: () => OnUpdateResult; + onlyOnOnlyP2P: () => OnUpdateResult; + onlyOnCouchDBOrMinIO: () => OnUpdateResult; + checkWorkingPassphrase: () => Promise; + isPassphraseValid: () => Promise; + rebuildDB: (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks") => Promise; + confirmRebuild(): Promise; + display(): void; + getMinioJournalSyncClient(): JournalSyncMinio; + resetRemoteBucket(): Promise; +} diff --git a/_types/modules/features/SettingDialogue/PaneAdvanced.d.ts b/_types/modules/features/SettingDialogue/PaneAdvanced.d.ts new file mode 100644 index 0000000..cd832e4 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneAdvanced.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneAdvanced(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneChangeLog.d.ts b/_types/modules/features/SettingDialogue/PaneChangeLog.d.ts new file mode 100644 index 0000000..d4176f4 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneChangeLog.d.ts @@ -0,0 +1,2 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +export declare function paneChangeLog(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement): void; diff --git a/_types/modules/features/SettingDialogue/PaneCustomisationSync.d.ts b/_types/modules/features/SettingDialogue/PaneCustomisationSync.d.ts new file mode 100644 index 0000000..126db16 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneCustomisationSync.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneCustomisationSync(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneGeneral.d.ts b/_types/modules/features/SettingDialogue/PaneGeneral.d.ts new file mode 100644 index 0000000..ab42227 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneGeneral.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneGeneral(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel, addPane }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneHatch.d.ts b/_types/modules/features/SettingDialogue/PaneHatch.d.ts new file mode 100644 index 0000000..0c5eba8 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneHatch.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneHatch(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneMaintenance.d.ts b/_types/modules/features/SettingDialogue/PaneMaintenance.d.ts new file mode 100644 index 0000000..9c66ec2 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneMaintenance.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab"; +import { type PageFunctions } from "./SettingPane"; +export declare function paneMaintenance(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PanePatches.d.ts b/_types/modules/features/SettingDialogue/PanePatches.d.ts new file mode 100644 index 0000000..8793f45 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PanePatches.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PanePowerUsers.d.ts b/_types/modules/features/SettingDialogue/PanePowerUsers.d.ts new file mode 100644 index 0000000..eea50a9 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PanePowerUsers.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function panePowerUsers(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneRemoteConfig.d.ts b/_types/modules/features/SettingDialogue/PaneRemoteConfig.d.ts new file mode 100644 index 0000000..8239fa0 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneRemoteConfig.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneRemoteConfig(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel, addPane }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneSelector.d.ts b/_types/modules/features/SettingDialogue/PaneSelector.d.ts new file mode 100644 index 0000000..ca25dd7 --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneSelector.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneSelector(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneSetup.d.ts b/_types/modules/features/SettingDialogue/PaneSetup.d.ts new file mode 100644 index 0000000..a3dae6d --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneSetup.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneSetup(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel, addPane }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/PaneSyncSettings.d.ts b/_types/modules/features/SettingDialogue/PaneSyncSettings.d.ts new file mode 100644 index 0000000..0a2f78c --- /dev/null +++ b/_types/modules/features/SettingDialogue/PaneSyncSettings.d.ts @@ -0,0 +1,3 @@ +import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; +import type { PageFunctions } from "./SettingPane.ts"; +export declare function paneSyncSettings(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel, addPane }: PageFunctions): void; diff --git a/_types/modules/features/SettingDialogue/SettingPane.d.ts b/_types/modules/features/SettingDialogue/SettingPane.d.ts new file mode 100644 index 0000000..ee68fbd --- /dev/null +++ b/_types/modules/features/SettingDialogue/SettingPane.d.ts @@ -0,0 +1,36 @@ +import type { ConfigLevel } from "@lib/common/models/shared.definition.configNames"; +import type { AllSettingItemKey, AllSettings } from "./settingConstants"; +export declare const combineOnUpdate: (func1: OnUpdateFunc, func2: OnUpdateFunc) => OnUpdateFunc; +export declare const setLevelClass: (el: HTMLElement, level?: ConfigLevel) => void; +export declare function setStyle(el: HTMLElement, styleHead: string, condition: () => boolean): void; +export declare function visibleOnly(cond: () => boolean): OnUpdateFunc; +export declare function enableOnly(cond: () => boolean): OnUpdateFunc; +export type OnUpdateResult = { + visibility?: boolean; + disabled?: boolean; + classes?: string[]; + isCta?: boolean; + isWarning?: boolean; +}; +export type OnUpdateFunc = () => OnUpdateResult; +export type UpdateFunction = () => void; +export type OnSavedHandlerFunc = (value: AllSettings[T]) => Promise | void; +export type OnSavedHandler = { + key: T; + handler: OnSavedHandlerFunc; +}; +export declare function getLevelStr(level: ConfigLevel): "" | import("octagonal-wheels/common/types").TaggedType | import("octagonal-wheels/common/types").TaggedType | import("octagonal-wheels/common/types").TaggedType; +export type AutoWireOption = { + placeHolder?: string; + holdValue?: boolean; + isPassword?: boolean; + invert?: boolean; + onUpdate?: OnUpdateFunc; + obsolete?: boolean; +}; +export declare function findAttrFromParent(el: HTMLElement, attr: string): string; +export declare function wrapMemo(func: (arg: T) => void): (arg: T) => void; +export type PageFunctions = { + addPane: (parentEl: HTMLElement, title: string, icon: string, order: number, wizardHidden: boolean, level?: ConfigLevel) => Promise; + addPanel: (parentEl: HTMLElement, title: string, callback?: (el: HTMLDivElement) => void, func?: OnUpdateFunc, level?: ConfigLevel) => Promise; +}; diff --git a/_types/modules/features/SettingDialogue/SveltePanel.d.ts b/_types/modules/features/SettingDialogue/SveltePanel.d.ts new file mode 100644 index 0000000..957447d --- /dev/null +++ b/_types/modules/features/SettingDialogue/SveltePanel.d.ts @@ -0,0 +1,34 @@ +import { type Component } from "svelte"; +import { type Writable } from "svelte/store"; +/** + * Props passed to Svelte panels, containing a writable port + * to communicate with the panel + */ +export type SveltePanelProps = { + port: Writable; +}; +/** + * A class to manage a Svelte panel within Obsidian + * Especially useful for settings panels + */ +export declare class SveltePanel { + private _mountedComponent; + private _componentValue; + /** + * Creates a Svelte panel instance + * @param component Component to mount + * @param mountTo HTMLElement to mount the component to + * @param valueStore Optional writable store to bind to the component's port, if not provided a new one will be created + * @returns The SveltePanel instance + */ + constructor(component: Component>, mountTo: HTMLElement, valueStore?: Writable); + /** + * Destroys the Svelte panel instance by unmounting the component + */ + destroy(): void; + /** + * Gets or sets the current value of the component's port + */ + get componentValue(): T | undefined; + set componentValue(value: T | undefined); +} diff --git a/_types/modules/features/SettingDialogue/remoteConfigBuffer.d.ts b/_types/modules/features/SettingDialogue/remoteConfigBuffer.d.ts new file mode 100644 index 0000000..56e68cc --- /dev/null +++ b/_types/modules/features/SettingDialogue/remoteConfigBuffer.d.ts @@ -0,0 +1,2 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +export declare function syncActivatedRemoteSettings(target: Partial, source: ObsidianLiveSyncSettings): void; diff --git a/_types/modules/features/SettingDialogue/settingConstants.d.ts b/_types/modules/features/SettingDialogue/settingConstants.d.ts new file mode 100644 index 0000000..0c2f3b8 --- /dev/null +++ b/_types/modules/features/SettingDialogue/settingConstants.d.ts @@ -0,0 +1 @@ +export * from "@lib/common/settingConstants.ts"; diff --git a/_types/modules/features/SettingDialogue/settingUtils.d.ts b/_types/modules/features/SettingDialogue/settingUtils.d.ts new file mode 100644 index 0000000..3a819aa --- /dev/null +++ b/_types/modules/features/SettingDialogue/settingUtils.d.ts @@ -0,0 +1,57 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +/** + * Generates a summary of P2P configuration settings + * @param setting Settings object + * @param additional Additional summary information to include + * @param showAdvanced Whether to include advanced settings + * @returns Summary object + */ +export declare function getP2PConfigSummary(setting: ObsidianLiveSyncSettings, additional?: Record, showAdvanced?: boolean): { + [x: string]: string; +}; +/** + * Generates a summary of Object Storage configuration settings + * @param setting Settings object + * @param showAdvanced Whether to include advanced settings + * @returns Summary object + */ +export declare function getBucketConfigSummary(setting: ObsidianLiveSyncSettings, showAdvanced?: boolean): Record; +/** + * Generates a summary of CouchDB configuration settings + * @param setting Settings object + * @param showAdvanced Whether to include advanced settings + * @returns Summary object + */ +export declare function getCouchDBConfigSummary(setting: ObsidianLiveSyncSettings, showAdvanced?: boolean): Record; +/** + * Generates a summary of E2EE configuration settings + * @param setting Settings object + * @param showAdvanced Whether to include advanced settings + * @returns Summary object + */ +export declare function getE2EEConfigSummary(setting: ObsidianLiveSyncSettings, showAdvanced?: boolean): Record; +/** + * Converts partial settings into a summary object + * @param setting Partial settings object + * @param showAdvanced Whether to include advanced settings + * @returns Summary object + */ +export declare function getSummaryFromPartialSettings(setting: Partial, showAdvanced?: boolean): Record; +/** + * Copy document from one database to another for migration purposes + * @param docName document ID + * @param dbFrom source database + * @param dbTo destination database + * @returns + */ +export declare function copyMigrationDocs(docName: string, dbFrom: PouchDB.Database, dbTo: PouchDB.Database): Promise; +type PouchDBOpenFunction = () => Promise | PouchDB.Database; +/** + * Migrate databases from one to another + * @param operationName Name of the migration operation + * @param from source database + * @param openTo function to open destination database + * @returns True if migration succeeded + */ +export declare function migrateDatabases(operationName: string, from: PouchDB.Database, openTo: PouchDBOpenFunction): Promise; +export {}; diff --git a/_types/modules/features/SetupManager.d.ts b/_types/modules/features/SetupManager.d.ts new file mode 100644 index 0000000..c38f253 --- /dev/null +++ b/_types/modules/features/SetupManager.d.ts @@ -0,0 +1,119 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import { AbstractModule } from "@/modules/AbstractModule.ts"; +/** + * User modes for onboarding and setup + */ +export declare const enum UserMode { + /** + * New User Mode - for users who are new to the plugin + */ + NewUser = "new-user", + /** + * Existing User Mode - for users who have used the plugin before, or just configuring again + */ + ExistingUser = "existing-user", + /** + * Unknown User Mode - for cases where the user mode is not determined + */ + Unknown = "unknown", + /** + * Update User Mode - for users who are updating configuration. May be `existing-user` as well, but possibly they want to treat it differently. + */ + Update = "unknown" +} +/** + * Setup Manager to handle onboarding and configuration setup + */ +export declare class SetupManager extends AbstractModule { + get dialogManager(): import("../../lib/src/UI/svelteDialog.ts").SvelteDialogManagerBase; + /** + * Starts the onboarding process + * @returns Promise that resolves to true if onboarding completed successfully, false otherwise + */ + startOnBoarding(): Promise; + /** + * Handles the onboarding process based on user mode + * @param userMode + * @returns Promise that resolves to true if onboarding completed successfully, false otherwise + */ + onOnboard(userMode: UserMode): Promise; + /** + * Handles setup using a setup URI + * @param userMode + * @param setupURI + * @returns Promise that resolves to true if onboarding completed successfully, false otherwise + */ + onUseSetupURI(userMode: UserMode, setupURI?: string): Promise; + /** + * Handles manual setup for CouchDB + * @param userMode + * @param currentSetting + * @param activate Whether to activate the CouchDB as remote type + * @returns Promise that resolves to true if setup completed successfully, false otherwise + */ + onCouchDBManualSetup(userMode: UserMode, currentSetting: ObsidianLiveSyncSettings, activate?: boolean): Promise; + /** + * Handles manual setup for S3-compatible bucket + * @param userMode + * @param currentSetting + * @param activate Whether to activate the Bucket as remote type + * @returns Promise that resolves to true if setup completed successfully, false otherwise + */ + onBucketManualSetup(userMode: UserMode, currentSetting: ObsidianLiveSyncSettings, activate?: boolean): Promise; + /** + * Handles manual setup for P2P + * @param userMode + * @param currentSetting + * @param activate Whether to activate the P2P as remote type (as P2P Only setup) + * @returns Promise that resolves to true if setup completed successfully, false otherwise + */ + onP2PManualSetup(userMode: UserMode, currentSetting: ObsidianLiveSyncSettings, activate?: boolean): Promise; + /** + * Handles only E2EE configuration + * @param userMode + * @param currentSetting + * @returns + */ + onlyE2EEConfiguration(userMode: UserMode, currentSetting: ObsidianLiveSyncSettings): Promise; + /** + * Handles manual configuration flow (E2EE + select server) + * @param originalSetting + * @param userMode + * @returns + */ + onConfigureManually(originalSetting: ObsidianLiveSyncSettings, userMode: UserMode): Promise; + /** + * Handles server selection during manual configuration + * @param currentSetting + * @param userMode + * @returns + */ + onSelectServer(currentSetting: ObsidianLiveSyncSettings, userMode: UserMode): Promise; + /** + * Confirms and applies settings obtained from the wizard + * @param newConf + * @param _userMode + * @param activate Whether to activate the remote type in the new settings + * @param extra Extra function to run before applying settings + * @returns Promise that resolves to true if settings applied successfully, false otherwise + */ + onConfirmApplySettingsFromWizard(newConf: ObsidianLiveSyncSettings, _userMode: UserMode, activate?: boolean, extra?: () => void): Promise; + /** + * Prompts the user with QR code scanning instructions + * @returns Promise that resolves to false as QR code instruction dialog does not yield settings directly + */ + onPromptQRCodeInstruction(): Promise; + /** + * Decodes settings from a QR code string and applies them + * @param qr QR code string containing encoded settings + * @returns Promise that resolves to true if settings applied successfully, false otherwise + */ + decodeQR(qr: string): Promise; + /** + * Applies the new settings to the core settings and saves them + * @param newConf + * @param userMode + * @returns Promise that resolves to true if settings applied successfully, false otherwise + */ + applySetting(newConf: ObsidianLiveSyncSettings, userMode: UserMode): Promise; +} diff --git a/_types/modules/features/SetupWizard/dialogs/setupDialogTypes.d.ts b/_types/modules/features/SetupWizard/dialogs/setupDialogTypes.d.ts new file mode 100644 index 0000000..322d6ee --- /dev/null +++ b/_types/modules/features/SetupWizard/dialogs/setupDialogTypes.d.ts @@ -0,0 +1,49 @@ +import type { BucketSyncSetting, CouchDBConnection, EncryptionSettings, ObsidianLiveSyncSettings, P2PConnectionInfo } from "@lib/common/models/setting.type"; +export declare const TYPE_IDENTICAL = "identical"; +export declare const TYPE_INDEPENDENT = "independent"; +export declare const TYPE_UNBALANCED = "unbalanced"; +export declare const TYPE_CANCEL = "cancelled"; +export declare const TYPE_BACKUP_DONE = "backup_done"; +export declare const TYPE_BACKUP_SKIPPED = "backup_skipped"; +export declare const TYPE_UNABLE_TO_BACKUP = "unable_to_backup"; +export declare const TYPE_NEW_USER = "new-user"; +export declare const TYPE_EXISTING_USER = "existing-user"; +export declare const TYPE_CANCELLED = "cancelled"; +export declare const TYPE_EXISTING = "existing-user"; +export declare const TYPE_NEW = "new-user"; +export declare const TYPE_COMPATIBLE_EXISTING = "compatible-existing-user"; +export declare const TYPE_APPLY = "apply"; +export declare const TYPE_USE_SETUP_URI = "use-setup-uri"; +export declare const TYPE_SCAN_QR_CODE = "scan-qr-code"; +export declare const TYPE_CONFIGURE_MANUALLY = "configure-manually"; +export declare const TYPE_CLOSE = "close"; +export declare const TYPE_COUCHDB = "couchdb"; +export declare const TYPE_BUCKET = "bucket"; +export declare const TYPE_P2P = "p2p"; +export type ResultTypeVault = typeof TYPE_IDENTICAL | typeof TYPE_INDEPENDENT | typeof TYPE_UNBALANCED | typeof TYPE_CANCEL; +export type ResultTypeBackup = typeof TYPE_BACKUP_DONE | typeof TYPE_BACKUP_SKIPPED | typeof TYPE_UNABLE_TO_BACKUP | typeof TYPE_CANCEL; +export type ResultTypeExtra = { + preventFetchingConfig: boolean; +}; +export type FetchEverythingResult = { + vault: ResultTypeVault; + backup: ResultTypeBackup; + extra: ResultTypeExtra; +} | typeof TYPE_CANCEL; +export type RebuildEverythingResult = { + backup: ResultTypeBackup; + extra: ResultTypeExtra; +} | typeof TYPE_CANCEL; +export type IntroResultType = typeof TYPE_NEW_USER | typeof TYPE_EXISTING_USER | typeof TYPE_CANCELLED; +export type OutroAskUserModeResultType = typeof TYPE_EXISTING | typeof TYPE_NEW | typeof TYPE_COMPATIBLE_EXISTING | typeof TYPE_CANCELLED; +export type OutroExistingUserResultType = typeof TYPE_APPLY | typeof TYPE_CANCELLED; +export type OutroNewUserResultType = typeof TYPE_APPLY | typeof TYPE_CANCELLED; +export type SelectMethodNewUserResultType = typeof TYPE_USE_SETUP_URI | typeof TYPE_CONFIGURE_MANUALLY | typeof TYPE_CANCELLED; +export type SelectMethodExistingResultType = typeof TYPE_USE_SETUP_URI | typeof TYPE_SCAN_QR_CODE | typeof TYPE_CONFIGURE_MANUALLY | typeof TYPE_CANCELLED; +export type SetupRemoteResultType = typeof TYPE_COUCHDB | typeof TYPE_BUCKET | typeof TYPE_P2P | typeof TYPE_CANCELLED; +export type UseSetupURIResultType = typeof TYPE_CANCELLED | ObsidianLiveSyncSettings; +export type SetupRemoteE2EEResultType = typeof TYPE_CANCELLED | EncryptionSettings; +export type SetupRemoteBucketResultType = typeof TYPE_CANCELLED | BucketSyncSetting; +export type SetupRemoteCouchDBResultType = typeof TYPE_CANCELLED | CouchDBConnection; +export type SetupRemoteP2PResultType = typeof TYPE_CANCELLED | P2PConnectionInfo; +export type ScanQRCodeResultType = typeof TYPE_CLOSE; diff --git a/_types/modules/main/ModuleLiveSyncMain.d.ts b/_types/modules/main/ModuleLiveSyncMain.d.ts new file mode 100644 index 0000000..5f178a1 --- /dev/null +++ b/_types/modules/main/ModuleLiveSyncMain.d.ts @@ -0,0 +1,9 @@ +import { AbstractModule } from "@/modules/AbstractModule.ts"; +import type { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub.ts"; +import type { LiveSyncCore } from "@/main.ts"; +export declare class ModuleLiveSyncMain extends AbstractModule { + _onLiveSyncReady(): Promise; + _wireUpEvents(): Promise; + _onLiveSyncLoad(): Promise; + onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void; +} diff --git a/_types/modules/services/ObsidianAPIService.d.ts b/_types/modules/services/ObsidianAPIService.d.ts new file mode 100644 index 0000000..df33c1e --- /dev/null +++ b/_types/modules/services/ObsidianAPIService.d.ts @@ -0,0 +1,39 @@ +import { InjectableAPIService } from "@lib/services/implements/injectable/InjectableAPIService"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import { type Command, type ViewCreator } from "obsidian"; +import { ObsHttpHandler } from "@/modules/essentialObsidian/APILib/ObsHttpHandler"; +import type { Confirm } from "@lib/interfaces/Confirm"; +declare module "obsidian" { + interface App { + appId?: string; + isMobile?: boolean; + } +} +export declare class ObsidianAPIService extends InjectableAPIService { + _customHandler: ObsHttpHandler | undefined; + _confirmInstance: Confirm; + constructor(context: ObsidianServiceContext); + getCustomFetchHandler(): ObsHttpHandler; + showWindow(viewType: string): Promise; + showWindowOnRight(viewType: string): Promise; + private get app(); + getPlatform(): string; + isMobile(): boolean; + getAppID(): string; + getSystemVaultName(): string; + getAppVersion(): string; + getPluginVersion(): string; + get confirm(): Confirm; + addCommand(command: TCommand): TCommand; + registerWindow(type: string, factory: ViewCreator): void; + addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => void): HTMLElement; + registerProtocolHandler(action: string, handler: (params: Record) => void): void; + /** + * In Obsidian, we will use the native `requestUrl` function as the default fetch handler, + * to address unavoidable CORS issues. + */ + nativeFetch(req: string | Request, opts?: RequestInit): Promise; + addStatusBarItem(): HTMLElement | undefined; + setInterval(handler: () => void, timeout: number): number; + getSystemConfigDir(): string; +} diff --git a/_types/modules/services/ObsidianAppLifecycleService.d.ts b/_types/modules/services/ObsidianAppLifecycleService.d.ts new file mode 100644 index 0000000..ad291dd --- /dev/null +++ b/_types/modules/services/ObsidianAppLifecycleService.d.ts @@ -0,0 +1,12 @@ +import { AppLifecycleServiceBase } from "@lib/services/implements/injectable/InjectableAppLifecycleService"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +declare module "obsidian" { + interface App { + commands: { + executeCommandById: (id: string) => Promise; + }; + } +} +export declare class ObsidianAppLifecycleService extends AppLifecycleServiceBase { + performRestart(): void; +} diff --git a/_types/modules/services/ObsidianConfirm.d.ts b/_types/modules/services/ObsidianConfirm.d.ts new file mode 100644 index 0000000..2dcccab --- /dev/null +++ b/_types/modules/services/ObsidianConfirm.d.ts @@ -0,0 +1,24 @@ +import { type App, type Plugin } from "@/deps"; +import type { Confirm } from "@lib/interfaces/Confirm"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +export declare class ObsidianConfirm implements Confirm { + private _context; + get _app(): App; + get _plugin(): Plugin; + constructor(context: T); + askYesNo(message: string): Promise<"yes" | "no">; + askString(title: string, key: string, placeholder: string, isPassword?: boolean): Promise; + askYesNoDialog(message: string, opt?: { + title?: string; + defaultOption?: "Yes" | "No"; + timeout?: number; + }): Promise<"yes" | "no">; + askSelectString(message: string, items: string[]): Promise; + askSelectStringDialogue(message: string, buttons: T, opt: { + title?: string; + defaultAction: T[number]; + timeout?: number; + }): Promise; + askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void): void; + confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>; +} diff --git a/_types/modules/services/ObsidianDatabaseService.d.ts b/_types/modules/services/ObsidianDatabaseService.d.ts new file mode 100644 index 0000000..484b082 --- /dev/null +++ b/_types/modules/services/ObsidianDatabaseService.d.ts @@ -0,0 +1,6 @@ +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import { DatabaseService, type DatabaseServiceDependencies } from "@lib/services/base/DatabaseService.ts"; +export declare class ObsidianDatabaseService extends DatabaseService { + private __onOpenDatabase; + constructor(context: T, dependencies: DatabaseServiceDependencies); +} diff --git a/_types/modules/services/ObsidianPathService.d.ts b/_types/modules/services/ObsidianPathService.d.ts new file mode 100644 index 0000000..80a9d21 --- /dev/null +++ b/_types/modules/services/ObsidianPathService.d.ts @@ -0,0 +1,12 @@ +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import { PathService } from "@lib/services/base/PathService"; +import { type BASE_IS_NEW, type TARGET_IS_NEW, type EVEN } from "@/common/utils"; +import type { UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type"; +import type { AnyEntry, FilePathWithPrefix } from "@lib/common/models/db.type"; +export declare class ObsidianPathService extends PathService { + markChangesAreSame(old: UXFileInfo | AnyEntry | FilePathWithPrefix, newMtime: number, oldMtime: number): boolean | undefined; + unmarkChanges(file: AnyEntry | FilePathWithPrefix | UXFileInfoStub): void; + compareFileFreshness(baseFile: UXFileInfoStub | AnyEntry | undefined, checkTarget: UXFileInfo | AnyEntry | undefined): typeof BASE_IS_NEW | typeof TARGET_IS_NEW | typeof EVEN; + isMarkedAsSameChanges(file: UXFileInfoStub | AnyEntry | FilePathWithPrefix, mtimes: number[]): undefined | typeof EVEN; + protected normalizePath(path: string): string; +} diff --git a/_types/modules/services/ObsidianServiceHub.d.ts b/_types/modules/services/ObsidianServiceHub.d.ts new file mode 100644 index 0000000..25c0d0b --- /dev/null +++ b/_types/modules/services/ObsidianServiceHub.d.ts @@ -0,0 +1,6 @@ +import { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub"; +import { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import type ObsidianLiveSyncPlugin from "@/main"; +export declare class ObsidianServiceHub extends InjectableServiceHub { + constructor(plugin: ObsidianLiveSyncPlugin); +} diff --git a/_types/modules/services/ObsidianServices.d.ts b/_types/modules/services/ObsidianServices.d.ts new file mode 100644 index 0000000..102772f --- /dev/null +++ b/_types/modules/services/ObsidianServices.d.ts @@ -0,0 +1,34 @@ +import { InjectableConflictService } from "@lib/services/implements/injectable/InjectableConflictService"; +import { InjectableDatabaseEventService } from "@lib/services/implements/injectable/InjectableDatabaseEventService"; +import { InjectableFileProcessingService } from "@lib/services/implements/injectable/InjectableFileProcessingService"; +import { InjectableRemoteService } from "@lib/services/implements/injectable/InjectableRemoteService"; +import { InjectableReplicationService } from "@lib/services/implements/injectable/InjectableReplicationService"; +import { InjectableReplicatorService } from "@lib/services/implements/injectable/InjectableReplicatorService"; +import { InjectableTestService } from "@lib/services/implements/injectable/InjectableTestService"; +import { InjectableTweakValueService } from "@lib/services/implements/injectable/InjectableTweakValueService"; +import { ConfigServiceBrowserCompat } from "@lib/services/implements/browser/ConfigServiceBrowserCompat"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext.ts"; +import { KeyValueDBService } from "@lib/services/base/KeyValueDBService"; +import { ControlService } from "@lib/services/base/ControlService"; +export declare class ObsidianDatabaseEventService extends InjectableDatabaseEventService { +} +export declare class ObsidianReplicatorService extends InjectableReplicatorService { +} +export declare class ObsidianFileProcessingService extends InjectableFileProcessingService { +} +export declare class ObsidianReplicationService extends InjectableReplicationService { +} +export declare class ObsidianRemoteService extends InjectableRemoteService { +} +export declare class ObsidianConflictService extends InjectableConflictService { +} +export declare class ObsidianTweakValueService extends InjectableTweakValueService { +} +export declare class ObsidianTestService extends InjectableTestService { +} +export declare class ObsidianConfigService extends ConfigServiceBrowserCompat { +} +export declare class ObsidianKeyValueDBService extends KeyValueDBService { +} +export declare class ObsidianControlService extends ControlService { +} diff --git a/_types/modules/services/ObsidianSettingService.d.ts b/_types/modules/services/ObsidianSettingService.d.ts new file mode 100644 index 0000000..f456ef2 --- /dev/null +++ b/_types/modules/services/ObsidianSettingService.d.ts @@ -0,0 +1,11 @@ +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +import { SettingService, type SettingServiceDependencies } from "@lib/services/base/SettingService"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +export declare class ObsidianSettingService extends SettingService { + constructor(context: T, dependencies: SettingServiceDependencies); + protected setItem(key: string, value: string): void; + protected getItem(key: string): string; + protected deleteItem(key: string): void; + protected saveData(data: ObsidianLiveSyncSettings): Promise; + protected loadData(): Promise; +} diff --git a/_types/modules/services/ObsidianUIService.d.ts b/_types/modules/services/ObsidianUIService.d.ts new file mode 100644 index 0000000..162bc3b --- /dev/null +++ b/_types/modules/services/ObsidianUIService.d.ts @@ -0,0 +1,17 @@ +import type { ConfigService } from "@lib/services/base/ConfigService"; +import type { AppLifecycleService } from "@lib/services/base/AppLifecycleService"; +import type { ReplicatorService } from "@lib/services/base/ReplicatorService"; +import { UIService } from "@lib/services//implements/base/UIService"; +import { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import type { IAPIService, IControlService } from "@lib/services/base/IService"; +export type ObsidianUIServiceDependencies = { + appLifecycle: AppLifecycleService; + config: ConfigService; + replicator: ReplicatorService; + APIService: IAPIService; + control: IControlService; +}; +export declare class ObsidianUIService extends UIService { + get dialogToCopy(): import("svelte/legacy").LegacyComponentType; + constructor(context: ObsidianServiceContext, dependents: ObsidianUIServiceDependencies); +} diff --git a/_types/modules/services/ObsidianVaultService.d.ts b/_types/modules/services/ObsidianVaultService.d.ts new file mode 100644 index 0000000..cf4086c --- /dev/null +++ b/_types/modules/services/ObsidianVaultService.d.ts @@ -0,0 +1,15 @@ +import { InjectableVaultService } from "@lib/services/implements/injectable/InjectableVaultService"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import type { FilePath } from "@lib/common/models/db.type"; +declare module "obsidian" { + interface DataAdapter { + insensitive?: boolean; + } +} +export declare class ObsidianVaultService extends InjectableVaultService { + vaultName(): string; + getActiveFilePath(): FilePath | undefined; + isStorageInsensitive(): boolean; + shouldCheckCaseInsensitively(): boolean; + isValidPath(path: string): boolean; +} diff --git a/_types/modules/services/SvelteDialogObsidian.d.ts b/_types/modules/services/SvelteDialogObsidian.d.ts new file mode 100644 index 0000000..1d7077f --- /dev/null +++ b/_types/modules/services/SvelteDialogObsidian.d.ts @@ -0,0 +1,9 @@ +import { SvelteDialogManagerBase, type ComponentHasResult, type SvelteDialogManagerDependencies } from "@lib/services/implements/base/SvelteDialog"; +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +export declare const SvelteDialogBase: any; +export declare class SvelteDialogObsidian extends SvelteDialogBase { + constructor(context: C, dependents: SvelteDialogManagerDependencies, component: ComponentHasResult, initialData?: U); +} +export declare class ObsidianSvelteDialogManager extends SvelteDialogManagerBase { + openSvelteDialog(component: ComponentHasResult, initialData?: TU): Promise; +} diff --git a/_types/serviceFeatures/onLayoutReady/enablei18n.d.ts b/_types/serviceFeatures/onLayoutReady/enablei18n.d.ts new file mode 100644 index 0000000..240ca2b --- /dev/null +++ b/_types/serviceFeatures/onLayoutReady/enablei18n.d.ts @@ -0,0 +1 @@ +export declare const enableI18nFeature: import("@lib/interfaces/ServiceModule").ServiceFeatureFunction, keyof import("@lib/interfaces/ServiceModule").ServiceModules, Promise>; diff --git a/_types/serviceFeatures/redFlag.d.ts b/_types/serviceFeatures/redFlag.d.ts new file mode 100644 index 0000000..4418489 --- /dev/null +++ b/_types/serviceFeatures/redFlag.d.ts @@ -0,0 +1,37 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +/** + * Flag file handler interface, similar to target filter pattern. + */ +interface FlagFileHandler { + priority: number; + check: () => Promise; + handle: () => Promise; +} +/** + * Factory function to create a fetch all flag handler. + * All logic related to fetch all flag is encapsulated here. + */ +export declare function createFetchAllFlagHandler(host: NecessaryServices<"vault" | "fileProcessing" | "tweakValue" | "UI" | "setting" | "appLifecycle" | "path" | "keyValueDB" | "database", "storageAccess" | "rebuilder" | "fileHandler">, log: LogFunction): FlagFileHandler; +/** + * Adjust setting to remote configuration. + * @param config current configuration to retrieve remote preferred config + * @returns updated configuration if applied, otherwise null. + */ +/** + * Factory function to create a rebuild flag handler. + * All logic related to rebuild flag is encapsulated here. + */ +export declare function createRebuildFlagHandler(host: NecessaryServices<"setting" | "appLifecycle" | "UI" | "tweakValue", "storageAccess" | "rebuilder">, log: LogFunction): { + priority: number; + check: () => Promise; + handle: () => Promise; +}; +/** + * Factory function to create a suspend all flag handler. + * All logic related to suspend flag is encapsulated here. + */ +export declare function createSuspendFlagHandler(host: NecessaryServices<"setting", "storageAccess">, log: LogFunction): FlagFileHandler; +export declare function flagHandlerToEventHandler(flagHandler: FlagFileHandler): () => Promise; +export declare function useRedFlagFeatures(host: NecessaryServices<"API" | "appLifecycle" | "UI" | "setting" | "tweakValue" | "fileProcessing" | "vault" | "path" | "keyValueDB" | "database", "storageAccess" | "rebuilder" | "fileHandler">): void; +export {}; diff --git a/_types/serviceFeatures/redFlag.simpleFetch.d.ts b/_types/serviceFeatures/redFlag.simpleFetch.d.ts new file mode 100644 index 0000000..090b997 --- /dev/null +++ b/_types/serviceFeatures/redFlag.simpleFetch.d.ts @@ -0,0 +1,17 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +import { type FullScanOptions } from "@lib/serviceFeatures/offlineScanner"; +export declare const SIMPLE_FETCH_STAGE1_REMOTE_WINS = "Overwrite all with remote files"; +export declare const SIMPLE_FETCH_STAGE1_NEWER_WINS = "Compare time and take newer"; +export declare const SIMPLE_FETCH_STAGE1_LEGACY = "Use the detailed flow"; +export declare const SIMPLE_FETCH_STAGE1_CANCEL = "Cancel"; +export declare const SIMPLE_FETCH_STAGE2_REMOTE_DELETE_NONE = "Keep local files even if not on remote"; +export declare const SIMPLE_FETCH_STAGE2_REMOTE_DELETE_ALL = "Delete local files if not on remote"; +export declare const SIMPLE_FETCH_STAGE2_NEWER_CLEANUP = "Delete local files if deleted on remote"; +export declare const SIMPLE_FETCH_STAGE2_NEWER_SYNC_ALL = "Keep local files even if deleted on remote"; +export declare const STAGE2_ABORT = "Cancel all and reboot"; +export declare function askSimpleFetchMode(host: NecessaryServices<"UI" | "vault", "storageAccess">): Promise<{ + mode: string; + options: Partial; +} | "cancelled" | "aborted">; +export declare function askAndPerformFastSetupOnScheduledFetchAll(host: NecessaryServices<"vault" | "fileProcessing" | "tweakValue" | "UI" | "setting" | "appLifecycle" | "path" | "keyValueDB" | "database", "storageAccess" | "rebuilder" | "fileHandler">, log: LogFunction, cleanupFlag: () => Promise): Promise; diff --git a/_types/serviceFeatures/redFlag.utils.d.ts b/_types/serviceFeatures/redFlag.utils.d.ts new file mode 100644 index 0000000..a77d3da --- /dev/null +++ b/_types/serviceFeatures/redFlag.utils.d.ts @@ -0,0 +1,27 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { type LogFunction } from "@lib/services/lib/logUtils"; +import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type"; +export declare function isFlagFileExist(host: NecessaryServices, path: string): Promise; +export declare function deleteFlagFile(host: NecessaryServices, log: LogFunction, path: string): Promise; +/** + * Adjust setting to remote configuration. + * @param config current configuration to retrieve remote preferred config + * @returns updated configuration if applied, otherwise null. + */ +export declare function adjustSettingToRemote(host: NecessaryServices<"tweakValue" | "UI" | "setting", never>, log: LogFunction, config: ObsidianLiveSyncSettings): Promise; +/** + * Adjust setting to remote if needed. + * @param extra result of dialogues that may contain preventFetchingConfig flag (e.g, from FetchEverything or RebuildEverything) + * @param config current configuration to retrieve remote preferred config + */ +export declare function adjustSettingToRemoteIfNeeded(host: NecessaryServices<"tweakValue" | "UI" | "setting", never>, log: LogFunction, extra: { + preventFetchingConfig: boolean; +}, config: ObsidianLiveSyncSettings): Promise; +/** + * Process vault initialisation with suspending file watching and sync. + * @param proc process to be executed during initialisation, should return true if can be continued, false if app is unable to continue the process. + * @param keepSuspending whether to keep suspending file watching after the process. + * @returns result of the process, or false if error occurs. + */ +export declare function processVaultInitialisation(host: NecessaryServices<"setting", never>, log: LogFunction, proc: () => Promise, keepSuspending?: boolean): Promise; +export declare function verifyAndUnlockSuspension(host: NecessaryServices<"setting" | "appLifecycle" | "UI", never>, log: LogFunction): Promise; diff --git a/_types/serviceFeatures/setupObsidian/setupManagerHandlers.d.ts b/_types/serviceFeatures/setupObsidian/setupManagerHandlers.d.ts new file mode 100644 index 0000000..5c20258 --- /dev/null +++ b/_types/serviceFeatures/setupObsidian/setupManagerHandlers.d.ts @@ -0,0 +1,6 @@ +import { type SetupManager } from "@/modules/features/SetupManager"; +import type { SetupFeatureHost } from "@lib/serviceFeatures/setupObsidian/types"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +export declare function openSetupURI(setupManager: SetupManager): Promise; +export declare function openP2PSettings(host: SetupFeatureHost, setupManager: SetupManager): Promise; +export declare function useSetupManagerHandlersFeature(host: NecessaryServices<"API" | "UI" | "setting" | "appLifecycle", never>, setupManager: SetupManager): void; diff --git a/_types/serviceFeatures/setupObsidian/setupProtocol.d.ts b/_types/serviceFeatures/setupObsidian/setupProtocol.d.ts new file mode 100644 index 0000000..3cca7df --- /dev/null +++ b/_types/serviceFeatures/setupObsidian/setupProtocol.d.ts @@ -0,0 +1,6 @@ +import type { LogFunction } from "@lib/services/lib/logUtils"; +import type { SetupFeatureHost } from "@lib/serviceFeatures/setupObsidian/types"; +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { type SetupManager } from "@/modules/features/SetupManager"; +export declare function registerSetupProtocolHandler(host: SetupFeatureHost, log: LogFunction, setupManager: SetupManager): void; +export declare function useSetupProtocolFeature(host: NecessaryServices<"API" | "UI" | "setting" | "appLifecycle", never>, setupManager: SetupManager): void; diff --git a/_types/serviceFeatures/useP2PReplicatorUI.d.ts b/_types/serviceFeatures/useP2PReplicatorUI.d.ts new file mode 100644 index 0000000..8b66089 --- /dev/null +++ b/_types/serviceFeatures/useP2PReplicatorUI.d.ts @@ -0,0 +1,17 @@ +import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; +import { type UseP2PReplicatorResult } from "@lib/replication/trystero/UseP2PReplicatorResult"; +import { P2PLogCollector } from "@lib/replication/trystero/P2PLogCollector"; +import type { LiveSyncCore } from "@/main"; +/** + * ServiceFeature: P2P Replicator lifecycle management. + * Binds a LiveSyncTrysteroReplicator to the host's lifecycle events, + * following the same middleware style as useOfflineScanner. + * + * @param viewTypeAndFactory Optional [viewType, factory] pair for registering the P2P pane view. + * When provided, also registers commands and ribbon icon via services.API. + */ +export declare function useP2PReplicatorUI(host: NecessaryServices<"API" | "appLifecycle" | "setting" | "vault" | "database" | "databaseEvents" | "keyValueDB" | "replication" | "config" | "UI" | "replicator", never>, core: LiveSyncCore, replicator: UseP2PReplicatorResult): { + replicator: import("../lib/src/replication/trystero/LiveSyncTrysteroReplicator").LiveSyncTrysteroReplicator; + p2pLogCollector: P2PLogCollector; + storeP2PStatusLine: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource; +}; diff --git a/_types/serviceModules/DatabaseFileAccess.d.ts b/_types/serviceModules/DatabaseFileAccess.d.ts new file mode 100644 index 0000000..5eb443e --- /dev/null +++ b/_types/serviceModules/DatabaseFileAccess.d.ts @@ -0,0 +1,4 @@ +import type { DatabaseFileAccess } from "@lib/interfaces/DatabaseFileAccess.ts"; +import { ServiceDatabaseFileAccessBase } from "@lib/serviceModules/ServiceDatabaseFileAccessBase"; +export declare class ServiceDatabaseFileAccess extends ServiceDatabaseFileAccessBase implements DatabaseFileAccess { +} diff --git a/_types/serviceModules/FileAccessObsidian.d.ts b/_types/serviceModules/FileAccessObsidian.d.ts new file mode 100644 index 0000000..1292e97 --- /dev/null +++ b/_types/serviceModules/FileAccessObsidian.d.ts @@ -0,0 +1,10 @@ +import { type App } from "@/deps"; +import { FileAccessBase, type FileAccessBaseDependencies } from "@lib/serviceModules/FileAccessBase.ts"; +import { ObsidianFileSystemAdapter } from "./FileSystemAdapters/ObsidianFileSystemAdapter"; +/** + * Obsidian-specific implementation of FileAccessBase + * Uses ObsidianFileSystemAdapter for platform-specific operations + */ +export declare class FileAccessObsidian extends FileAccessBase { + constructor(app: App, dependencies: FileAccessBaseDependencies); +} diff --git a/_types/serviceModules/FileHandler.d.ts b/_types/serviceModules/FileHandler.d.ts new file mode 100644 index 0000000..de851d7 --- /dev/null +++ b/_types/serviceModules/FileHandler.d.ts @@ -0,0 +1,3 @@ +import { ServiceFileHandlerBase } from "@lib/serviceModules/ServiceFileHandlerBase"; +export declare class ServiceFileHandler extends ServiceFileHandlerBase { +} diff --git a/_types/serviceModules/FileSystemAdapters/ObsidianConversionAdapter.d.ts b/_types/serviceModules/FileSystemAdapters/ObsidianConversionAdapter.d.ts new file mode 100644 index 0000000..cac818d --- /dev/null +++ b/_types/serviceModules/FileSystemAdapters/ObsidianConversionAdapter.d.ts @@ -0,0 +1,10 @@ +import type { UXFileInfoStub, UXFolderInfo } from "@lib/common/models/fileaccess.type"; +import type { IConversionAdapter } from "@lib/serviceModules/adapters"; +import type { TFile, TFolder } from "obsidian"; +/** + * Conversion adapter implementation for Obsidian + */ +export declare class ObsidianConversionAdapter implements IConversionAdapter { + nativeFileToUXFileInfoStub(file: TFile): UXFileInfoStub; + nativeFolderToUXFolder(folder: TFolder): UXFolderInfo; +} diff --git a/_types/serviceModules/FileSystemAdapters/ObsidianFileSystemAdapter.d.ts b/_types/serviceModules/FileSystemAdapters/ObsidianFileSystemAdapter.d.ts new file mode 100644 index 0000000..c444304 --- /dev/null +++ b/_types/serviceModules/FileSystemAdapters/ObsidianFileSystemAdapter.d.ts @@ -0,0 +1,29 @@ +import type { FilePath } from "@lib/common/models/db.type"; +import type { UXStat } from "@lib/common/models/fileaccess.type"; +import type { IFileSystemAdapter, IPathAdapter, ITypeGuardAdapter, IConversionAdapter, IStorageAdapter, IVaultAdapter } from "@lib/serviceModules/adapters"; +import type { TAbstractFile, TFile, TFolder, Stat, App } from "obsidian"; +declare module "obsidian" { + interface Vault { + getAbstractFileByPathInsensitive(path: string): TAbstractFile | null; + } + interface DataAdapter { + reconcileInternalFile?(path: string): Promise; + } +} +/** + * Complete file system adapter implementation for Obsidian + */ +export declare class ObsidianFileSystemAdapter implements IFileSystemAdapter { + private app; + readonly path: IPathAdapter; + readonly typeGuard: ITypeGuardAdapter; + readonly conversion: IConversionAdapter; + readonly storage: IStorageAdapter; + readonly vault: IVaultAdapter; + constructor(app: App); + getAbstractFileByPath(path: FilePath | string): Promise; + getAbstractFileByPathInsensitive(path: FilePath | string): Promise; + getFiles(): Promise; + statFromNative(file: TFile): Promise; + reconcileInternalFile(path: string): Promise; +} diff --git a/_types/serviceModules/FileSystemAdapters/ObsidianPathAdapter.d.ts b/_types/serviceModules/FileSystemAdapters/ObsidianPathAdapter.d.ts new file mode 100644 index 0000000..7bc6bec --- /dev/null +++ b/_types/serviceModules/FileSystemAdapters/ObsidianPathAdapter.d.ts @@ -0,0 +1,10 @@ +import { type TAbstractFile } from "@/deps"; +import type { FilePath } from "@lib/common/models/db.type"; +import type { IPathAdapter } from "@lib/serviceModules/adapters"; +/** + * Path adapter implementation for Obsidian + */ +export declare class ObsidianPathAdapter implements IPathAdapter { + getPath(file: string | TAbstractFile): FilePath; + normalisePath(path: string): string; +} diff --git a/_types/serviceModules/FileSystemAdapters/ObsidianStorageAdapter.d.ts b/_types/serviceModules/FileSystemAdapters/ObsidianStorageAdapter.d.ts new file mode 100644 index 0000000..4796b38 --- /dev/null +++ b/_types/serviceModules/FileSystemAdapters/ObsidianStorageAdapter.d.ts @@ -0,0 +1,24 @@ +import type { UXDataWriteOptions } from "@lib/common/models/fileaccess.type"; +import type { IStorageAdapter } from "@lib/serviceModules/adapters"; +import type { Stat, App } from "obsidian"; +/** + * Storage adapter implementation for Obsidian + */ +export declare class ObsidianStorageAdapter implements IStorageAdapter { + private app; + constructor(app: App); + exists(path: string): Promise; + trystat(path: string): Promise; + stat(path: string): Promise; + mkdir(path: string): Promise; + remove(path: string): Promise; + read(path: string): Promise; + readBinary(path: string): Promise; + write(path: string, data: string, options?: UXDataWriteOptions): Promise; + writeBinary(path: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise; + append(path: string, data: string, options?: UXDataWriteOptions): Promise; + list(basePath: string): Promise<{ + files: string[]; + folders: string[]; + }>; +} diff --git a/_types/serviceModules/FileSystemAdapters/ObsidianTypeGuardAdapter.d.ts b/_types/serviceModules/FileSystemAdapters/ObsidianTypeGuardAdapter.d.ts new file mode 100644 index 0000000..78a0f65 --- /dev/null +++ b/_types/serviceModules/FileSystemAdapters/ObsidianTypeGuardAdapter.d.ts @@ -0,0 +1,9 @@ +import type { ITypeGuardAdapter } from "@lib/serviceModules/adapters"; +import { TFile, TFolder } from "obsidian"; +/** + * Type guard adapter implementation for Obsidian + */ +export declare class ObsidianTypeGuardAdapter implements ITypeGuardAdapter { + isFile(file: unknown): file is TFile; + isFolder(item: unknown): item is TFolder; +} diff --git a/_types/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.d.ts b/_types/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.d.ts new file mode 100644 index 0000000..42fd4c1 --- /dev/null +++ b/_types/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.d.ts @@ -0,0 +1,20 @@ +import type { UXDataWriteOptions } from "@lib/common/models/fileaccess.type"; +import type { IVaultAdapter } from "@lib/serviceModules/adapters"; +import type { TFile, App, TFolder } from "obsidian"; +/** + * Vault adapter implementation for Obsidian + */ +export declare class ObsidianVaultAdapter implements IVaultAdapter { + private app; + constructor(app: App); + read(file: TFile): Promise; + cachedRead(file: TFile): Promise; + readBinary(file: TFile): Promise; + modify(file: TFile, data: string, options?: UXDataWriteOptions): Promise; + modifyBinary(file: TFile, data: ArrayBuffer, options?: UXDataWriteOptions): Promise; + create(path: string, data: string, options?: UXDataWriteOptions): Promise; + createBinary(path: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise; + delete(file: TFile | TFolder, force?: boolean): Promise; + trash(file: TFile | TFolder, force?: boolean): Promise; + trigger(name: string, ...data: any[]): any; +} diff --git a/_types/serviceModules/ServiceFileAccessImpl.d.ts b/_types/serviceModules/ServiceFileAccessImpl.d.ts new file mode 100644 index 0000000..10e0cd7 --- /dev/null +++ b/_types/serviceModules/ServiceFileAccessImpl.d.ts @@ -0,0 +1,4 @@ +import { ServiceFileAccessBase } from "@lib/serviceModules/ServiceFileAccessBase"; +import type { ObsidianFileSystemAdapter } from "./FileSystemAdapters/ObsidianFileSystemAdapter"; +export declare class ServiceFileAccessObsidian extends ServiceFileAccessBase { +} diff --git a/_types/types.d.ts b/_types/types.d.ts new file mode 100644 index 0000000..717964b --- /dev/null +++ b/_types/types.d.ts @@ -0,0 +1,24 @@ +import type { DatabaseFileAccess } from "@lib/interfaces/DatabaseFileAccess"; +import type { Rebuilder } from "@lib/interfaces/DatabaseRebuilder"; +import type { IFileHandler } from "@lib/interfaces/FileHandler"; +import type { StorageAccess } from "@lib/interfaces/StorageAccess"; +import type { IServiceHub } from "@lib/services/base/IService"; +export interface ServiceModules { + storageAccess: StorageAccess; + /** + * Database File Accessor for handling file operations related to the database, such as exporting the database, importing from a file, etc. + */ + databaseFileAccess: DatabaseFileAccess; + /** + * File Handler for handling file operations related to replication, such as resolving conflicts, applying changes from replication, etc. + */ + fileHandler: IFileHandler; + /** + * Rebuilder for handling database rebuilding operations. + */ + rebuilder: Rebuilder; +} +export interface LiveSyncHost { + services: IServiceHub; + serviceModules: ServiceModules; +} diff --git a/generate-types.mjs b/generate-types.mjs new file mode 100644 index 0000000..616dbd0 --- /dev/null +++ b/generate-types.mjs @@ -0,0 +1,11 @@ +import { execSync } from "node:child_process"; + +try { + console.log("[Postbuild] Generating type definitions for fallback..."); + execSync("npx tsc -p tsconfig.types.json", { stdio: "inherit" }); + console.log("[Postbuild] Type definitions generated successfully."); +} catch (error) { + // Ignore compiler errors from tsc so that pre-existing type errors in the submodule + // do not block the build from succeeding. + console.warn("[Postbuild] Type definitions generated with some compilation warnings."); +} diff --git a/package.json b/package.json index 01e6c86..dd05a0d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "dev": "node --env-file=.env esbuild.config.mjs", "prebuild": "npm run bakei18n", "build": "node esbuild.config.mjs production", + "lib:build:types":"node generate-types.mjs", + "postbuild": "npm run lib:build:types", "buildVite": "npx dotenv-cli -e .env -- vite build --mode production", "buildViteOriginal": "npx dotenv-cli -e .env -- vite build --mode original", "buildDev": "node esbuild.config.mjs dev", diff --git a/tsconfig.json b/tsconfig.json index 7139443..4aa2cd3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ "strictFunctionTypes": true, "paths": { "@/*": ["./src/*"], - "@lib/*": ["./src/lib/src/*"] + "@lib/*": ["./src/lib/src/*", "./_types/src/lib/src/*"] } }, "include": ["**/*.ts", "test/**/*.test.ts", "**/*.unit.spec.ts"], diff --git a/tsconfig.types.json b/tsconfig.types.json new file mode 100644 index 0000000..c165eb1 --- /dev/null +++ b/tsconfig.types.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "./_types" + }, + "include": ["src/lib/**/*.ts"], + "exclude": [ + "_types", + "pouchdb-browser-webpack", + "utils", + "src/apps", + "src/**/*.test.ts", + "**/_test/**", + "utilsdeno", + "node_modules", + "test/**/*.test.ts", + "**/*.unit.spec.ts" + ] +}